]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Dedicated routines for poly1305 arithmetic.
authorSimon Tatham <anakin@pobox.com>
Sun, 7 Jun 2015 11:26:26 +0000 (12:26 +0100)
committerSimon Tatham <anakin@pobox.com>
Sun, 7 Jun 2015 12:50:05 +0000 (13:50 +0100)
Rather than doing arithmetic mod 2^130-5 using the general-purpose
Bignum library, which requires lots of mallocs and frees per operation
and also uses a general-purpose divide routine for each modular
reduction, we now have some dedicated routines in sshccp.c to do
arithmetic mod 2^130-5 in a more efficient way, and hopefully also
with data-independent performance.

Because PuTTY's target platforms don't all use the same size of bignum
component, I've arranged to auto-generate the arithmetic functions
using a Python script living in the 'contrib' directory. As and when
we need to support an extra BignumInt size, that script should still
be around to re-run with different arguments.

contrib/make1305.py [new file with mode: 0755]
sshccp.c

diff --git a/contrib/make1305.py b/contrib/make1305.py
new file mode 100755 (executable)
index 0000000..ede220d
--- /dev/null
@@ -0,0 +1,267 @@
+#!/usr/bin/env python
+
+import sys
+
+class Output(object):
+    def __init__(self, bignum_int_bits):
+        self.bignum_int_bits = bignum_int_bits
+        self.text = ""
+        self.vars = []
+    def stmt(self, statement):
+        self.text += "    %s;\n" % statement
+    def register_var(self, var):
+        self.vars.append(var)
+    def finalise(self):
+        for var in self.vars:
+            assert var.maxval == 0, "Variable not clear: %s" % var.name
+        return self.text
+
+class Variable(object):
+    def __init__(self, out, name):
+        self.out = out
+        self.maxval = 0
+        self.name = name
+        self.placeval = None
+        self.out.stmt("BignumDblInt %s" % (self.name))
+        self.out.register_var(self)
+    def clear(self, placeval):
+        self.maxval = 0
+        self.placeval = placeval
+        self.out.stmt("%s = 0" % (self.name))
+    def set_word(self, name, limit=None):
+        if limit is not None:
+            self.maxval = limit-1
+        else:
+            self.maxval = (1 << self.out.bignum_int_bits) - 1
+        assert self.maxval < (1 << 2*self.out.bignum_int_bits)
+        self.out.stmt("%s = %s" % (self.name, name))
+    def add_word(self, name, limit=None):
+        if limit is not None:
+            self.maxval += limit-1
+        else:
+            self.maxval += (1 << self.out.bignum_int_bits) - 1
+        assert self.maxval < (1 << 2*self.out.bignum_int_bits)
+        self.out.stmt("%s += %s" % (self.name, name))
+    def add_input_word(self, fmt, wordpos, limit=None):
+        assert self.placeval == wordpos * self.out.bignum_int_bits
+        self.add_word(fmt % wordpos, limit)
+    def set_to_product(self, a, b, placeval):
+        self.maxval = ((1 << self.out.bignum_int_bits) - 1) ** 2
+        assert self.maxval < (1 << 2*self.out.bignum_int_bits)        
+        self.out.stmt("%s = (BignumDblInt)(%s) * (%s)" % (self.name, a, b))
+        self.placeval = placeval
+    def add_bottom_half(self, srcvar):
+        self.add_word("%s & BIGNUM_INT_MASK" % (srcvar.name))
+    def add_top_half(self, srcvar):
+        self.add_word("%s >> %d" % (srcvar.name, self.out.bignum_int_bits))
+    def unload_into(self, topvar, botvar):
+        assert botvar.placeval == self.placeval
+        botvar.add_bottom_half(self)
+        assert topvar.placeval == self.placeval + self.out.bignum_int_bits
+        topvar.add_top_half(self)
+        self.maxval = 0
+    def output_word(self, bitpos, bits, destfmt, destwordpos):
+        assert bitpos == 0
+        assert self.placeval == destwordpos * self.out.bignum_int_bits
+        dest = destfmt % destwordpos
+        if bits == self.out.bignum_int_bits:
+            self.out.stmt("%s = %s" % (dest, self.name))
+        else:
+            self.out.stmt("%s = %s & (((BignumInt)1 << %d)-1)" %
+                          (dest, self.name, bits))
+    def transfer_to_next_acc(self, bitpos, bits, pow5, destvar):
+        destbitpos = self.placeval + bitpos - 130 * pow5 - destvar.placeval
+        #print "transfer", "*%d" % 5**pow5, self.name, self.placeval, bitpos, destvar.name, destvar.placeval, destbitpos, bits
+        assert 0 <= bitpos < bitpos+bits <= self.out.bignum_int_bits
+        assert 0 <= destbitpos < destbitpos+bits <= self.out.bignum_int_bits
+        expr = self.name
+        if bitpos > 0:
+            expr = "(%s >> %d)" % (expr, bitpos)
+        expr = "(%s & (((BignumInt)1 << %d)-1))" % (expr, bits)
+        self.out.stmt("%s += %s * ((BignumDblInt)%d << %d)" %
+                      (destvar.name, expr, 5**pow5, destbitpos))
+        destvar.maxval += (((1 << bits)-1) << destbitpos) * (5**pow5)
+    def shift_down_from(self, top):
+        if top is not None:
+            self.out.stmt("%s = %s + (%s >> %d)" %
+                          (self.name, top.name, self.name,
+                           self.out.bignum_int_bits))
+            topmaxval = top.maxval
+        else:
+            self.out.stmt("%s >>= %d" % (self.name, self.out.bignum_int_bits))
+            topmaxval = 0
+        self.maxval = topmaxval + self.maxval >> self.out.bignum_int_bits
+        assert self.maxval < (1 << 2*self.out.bignum_int_bits)
+        if top is not None:
+            assert self.placeval + self.out.bignum_int_bits == top.placeval
+            top.clear(top.placeval + self.out.bignum_int_bits)
+        self.placeval += self.out.bignum_int_bits
+
+def gen_add(bignum_int_bits):
+    out = Output(bignum_int_bits)
+
+    inbits = 130
+    inwords = (inbits + bignum_int_bits - 1) / bignum_int_bits
+
+    # This is an addition _without_ reduction mod p, so that it can be
+    # used both during accumulation of the polynomial and for adding
+    # on the encrypted nonce at the end (which is mod 2^128, not mod
+    # p).
+    #
+    # Because one of the inputs will have come from our
+    # not-completely-reducing multiplication function, we expect up to
+    # 3 extra bits of input.
+    acclo = Variable(out, "acclo")
+
+    acclo.clear(0)
+
+    for wordpos in range(inwords):
+        limit = min(1 << bignum_int_bits, 1 << (130 - wordpos*bignum_int_bits))
+        acclo.add_input_word("a->w[%d]", wordpos, limit)
+        acclo.add_input_word("b->w[%d]", wordpos, limit)
+        acclo.output_word(0, bignum_int_bits, "r->w[%d]", wordpos)
+        acclo.shift_down_from(None)
+
+    return out.finalise()
+
+def gen_mul_1305(bignum_int_bits):
+    out = Output(bignum_int_bits)
+
+    inbits = 130
+    inwords = (inbits + bignum_int_bits - 1) / bignum_int_bits
+
+    # The inputs are not 100% reduced mod p. Specifically, we can get
+    # a full 130-bit number from the pow5==0 pass, and then a 130-bit
+    # number times 5 from the pow5==1 pass, plus a possible carry. The
+    # total of that can be easily bounded above by 2^130 * 8, so we
+    # need to assume we're multiplying two 133-bit numbers.
+    outbits = (inbits + 3) * 2
+    outwords = (outbits + bignum_int_bits - 1) / bignum_int_bits + 1
+
+    tmp = Variable(out, "tmp")
+    acclo = Variable(out, "acclo")
+    acchi = Variable(out, "acchi")
+    acc2lo = Variable(out, "acc2lo")
+
+    pow5, bits_at_pow5 = 0, inbits
+
+    acclo.clear(0)
+    acchi.clear(bignum_int_bits)
+    bits_needed_in_acc2 = bignum_int_bits
+
+    for outwordpos in range(outwords):
+        for a in range(inwords):
+            b = outwordpos - a
+            if 0 <= b < inwords:
+                tmp.set_to_product("a->w[%d]" % a, "b->w[%d]" % b,
+                                   outwordpos * bignum_int_bits)
+                tmp.unload_into(acchi, acclo)
+
+        bits_in_word = bignum_int_bits
+        bitpos = 0
+        #print "begin output"
+        while bits_in_word > 0:
+            chunk = min(bits_in_word, bits_at_pow5)
+            if pow5 > 0:
+                chunk = min(chunk, bits_needed_in_acc2)
+            if pow5 == 0:
+                acclo.output_word(bitpos, chunk, "r->w[%d]", outwordpos)
+            else:
+                acclo.transfer_to_next_acc(bitpos, chunk, pow5, acc2lo)
+                bits_needed_in_acc2 -= chunk
+                if bits_needed_in_acc2 == 0:
+                    assert acc2lo.placeval % bignum_int_bits == 0
+                    other_outwordpos = acc2lo.placeval / bignum_int_bits
+                    acc2lo.add_input_word("r->w[%d]", other_outwordpos)
+                    acc2lo.output_word(bitpos, bignum_int_bits, "r->w[%d]",
+                                       other_outwordpos)
+                    acc2lo.shift_down_from(None)
+                    bits_needed_in_acc2 = bignum_int_bits
+            bits_in_word -= chunk
+            bits_at_pow5 -= chunk
+            bitpos += chunk
+            if bits_at_pow5 == 0:
+                if pow5 > 0:
+                    assert acc2lo.placeval % bignum_int_bits == 0
+                    other_outwordpos = acc2lo.placeval / bignum_int_bits
+                    acc2lo.add_input_word("r->w[%d]", other_outwordpos)
+                    acc2lo.output_word(0, bignum_int_bits, "r->w[%d]",
+                                       other_outwordpos)
+                pow5 += 1
+                bits_at_pow5 = inbits
+                acc2lo.clear(0)
+                bits_needed_in_acc2 = bignum_int_bits
+        acclo.shift_down_from(acchi)
+
+    while acc2lo.maxval > 0:
+        other_outwordpos = acc2lo.placeval / bignum_int_bits
+        bitsleft = inbits - other_outwordpos * bignum_int_bits
+        limit = 1<<bitsleft if bitsleft < bignum_int_bits else None
+        acc2lo.add_input_word("r->w[%d]", other_outwordpos, limit=limit)
+        acc2lo.output_word(0, bignum_int_bits, "r->w[%d]", other_outwordpos)
+        acc2lo.shift_down_from(None)
+
+    return out.finalise()
+
+def gen_final_reduce_1305(bignum_int_bits):
+    out = Output(bignum_int_bits)
+
+    inbits = 130
+    inwords = (inbits + bignum_int_bits - 1) / bignum_int_bits
+
+    # We take our input number n, and compute k = 5 + 5*(n >> 130).
+    # Then k >> 130 is precisely the multiple of p that needs to be
+    # subtracted from n to reduce it to strictly less than p.
+
+    acclo = Variable(out, "acclo")
+
+    acclo.clear(0)
+    # Hopefully all the bits we're shifting down fit in the same word.
+    assert 130 / bignum_int_bits == (130 + 3 - 1) / bignum_int_bits
+    acclo.add_word("5 * ((n->w[%d] >> %d) + 1)" %
+                   (130 / bignum_int_bits, 130 % bignum_int_bits),
+                   limit = 5 * (7 + 1))
+    for wordpos in range(inwords):
+        acclo.add_input_word("n->w[%d]", wordpos)
+        # Notionally, we could call acclo.output_word here to store
+        # our adjusted value k. But we don't need to, because all we
+        # actually want is the very top word of it.
+        if wordpos == 130 / bignum_int_bits:
+            break
+        acclo.shift_down_from(None)
+
+    # Now we can find the right multiple of p to subtract. We actually
+    # subtract it by adding 5 times it, and then finally discarding
+    # the top bits of the output.
+
+    # Hopefully all the bits we're shifting down fit in the same word.
+    assert 130 / bignum_int_bits == (130 + 3 - 1) / bignum_int_bits
+    acclo.set_word("5 * (acclo >> %d)" % (130 % bignum_int_bits),
+                   limit = 5 * (7 + 1))
+    acclo.placeval = 0
+    for wordpos in range(inwords):
+        acclo.add_input_word("n->w[%d]", wordpos)
+        acclo.output_word(0, bignum_int_bits, "n->w[%d]", wordpos)
+        acclo.shift_down_from(None)
+
+    out.stmt("n->w[%d] &= (1 << %d) - 1" %
+             (130 / bignum_int_bits, 130 % bignum_int_bits))
+
+    # Here we don't call out.finalise(), because that will complain
+    # that there are bits of output we never dealt with. This is true,
+    # but all the bits in question are above 2^130, so they're bits
+    # we're discarding anyway.
+    return out.text # not out.finalise()
+
+ops = { "mul" : gen_mul_1305,
+        "add" : gen_add,
+        "final_reduce" : gen_final_reduce_1305 }
+
+args = sys.argv[1:]
+if len(args) != 2 or args[0] not in ops:
+    sys.stderr.write("usage: make1305.py (%s) <bits>\n" % (" | ".join(sorted(ops))))
+    sys.exit(1)
+
+sys.stdout.write("    /* ./contrib/make1305.py %s %s */\n" % tuple(args))
+s = ops[args[0]](int(args[1]))
+sys.stdout.write(s)
index 51a714505ac368adfc36b6deadf3aa430435d2b4..df973e63d788abe6af3326edd04ba0c74f0c7d50 100644 (file)
--- a/sshccp.c
+++ b/sshccp.c
@@ -30,6 +30,7 @@
  */
 
 #include "ssh.h"
+#include "sshbn.h"
 
 #ifndef INLINE
 #define INLINE
@@ -179,44 +180,746 @@ static INLINE void chacha20_decrypt(struct chacha20 *ctx,
 
 /* Poly1305 implementation (no AES, nonce is not encrypted) */
 
+#define NWORDS ((130 + BIGNUM_INT_BITS-1) / BIGNUM_INT_BITS)
+typedef struct bigval {
+    BignumInt w[NWORDS];
+} bigval;
+
+static void bigval_clear(bigval *r)
+{
+    int i;
+    for (i = 0; i < NWORDS; i++)
+        r->w[i] = 0;
+}
+
+static void bigval_import_le(bigval *r, const void *vdata, int len)
+{
+    const unsigned char *data = (const unsigned char *)vdata;
+    int i;
+    bigval_clear(r);
+    for (i = 0; i < len; i++)
+        r->w[i / BIGNUM_INT_BYTES] |= data[i] << (8 * (i % BIGNUM_INT_BYTES));
+}
+
+static void bigval_export_le(const bigval *r, void *vdata, int len)
+{
+    unsigned char *data = (unsigned char *)vdata;
+    int i;
+    for (i = 0; i < len; i++)
+        data[i] = r->w[i / BIGNUM_INT_BYTES] >> (8 * (i % BIGNUM_INT_BYTES));
+}
+
+/*
+ * Addition of bigvals, not mod p.
+ */
+static void bigval_add(bigval *r, const bigval *a, const bigval *b)
+{
+#if BIGNUM_INT_BITS == 32
+    /* ./contrib/make1305.py add 32 */
+    BignumDblInt acclo;
+    acclo = 0;
+    acclo += a->w[0];
+    acclo += b->w[0];
+    r->w[0] = acclo;
+    acclo >>= 32;
+    acclo += a->w[1];
+    acclo += b->w[1];
+    r->w[1] = acclo;
+    acclo >>= 32;
+    acclo += a->w[2];
+    acclo += b->w[2];
+    r->w[2] = acclo;
+    acclo >>= 32;
+    acclo += a->w[3];
+    acclo += b->w[3];
+    r->w[3] = acclo;
+    acclo >>= 32;
+    acclo += a->w[4];
+    acclo += b->w[4];
+    r->w[4] = acclo;
+    acclo >>= 32;
+#elif BIGNUM_INT_BITS == 16
+    /* ./contrib/make1305.py add 16 */
+    BignumDblInt acclo;
+    acclo = 0;
+    acclo += a->w[0];
+    acclo += b->w[0];
+    r->w[0] = acclo;
+    acclo >>= 16;
+    acclo += a->w[1];
+    acclo += b->w[1];
+    r->w[1] = acclo;
+    acclo >>= 16;
+    acclo += a->w[2];
+    acclo += b->w[2];
+    r->w[2] = acclo;
+    acclo >>= 16;
+    acclo += a->w[3];
+    acclo += b->w[3];
+    r->w[3] = acclo;
+    acclo >>= 16;
+    acclo += a->w[4];
+    acclo += b->w[4];
+    r->w[4] = acclo;
+    acclo >>= 16;
+    acclo += a->w[5];
+    acclo += b->w[5];
+    r->w[5] = acclo;
+    acclo >>= 16;
+    acclo += a->w[6];
+    acclo += b->w[6];
+    r->w[6] = acclo;
+    acclo >>= 16;
+    acclo += a->w[7];
+    acclo += b->w[7];
+    r->w[7] = acclo;
+    acclo >>= 16;
+    acclo += a->w[8];
+    acclo += b->w[8];
+    r->w[8] = acclo;
+    acclo >>= 16;
+#else
+#error Run contrib/make1305.py again with a different bit count
+#endif
+}
+
+/*
+ * Multiplication of bigvals mod p. Uses r as temporary storage, so
+ * don't pass r aliasing a or b.
+ */
+static void bigval_mul_mod_p(bigval *r, const bigval *a, const bigval *b)
+{
+#if BIGNUM_INT_BITS == 32
+    /* ./contrib/make1305.py mul 32 */
+    BignumDblInt tmp;
+    BignumDblInt acclo;
+    BignumDblInt acchi;
+    BignumDblInt acc2lo;
+    acclo = 0;
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    r->w[0] = acclo;
+    acclo = acchi + (acclo >> 32);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    r->w[1] = acclo;
+    acclo = acchi + (acclo >> 32);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    r->w[2] = acclo;
+    acclo = acchi + (acclo >> 32);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    r->w[3] = acclo;
+    acclo = acchi + (acclo >> 32);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    r->w[4] = acclo & (((BignumInt)1 << 2)-1);
+    acc2lo = 0;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 30)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 32);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 30);
+    acc2lo += r->w[0];
+    r->w[0] = acc2lo;
+    acc2lo >>= 32;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 30)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 32);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 30);
+    acc2lo += r->w[1];
+    r->w[1] = acc2lo;
+    acc2lo >>= 32;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 30)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 32);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 30);
+    acc2lo += r->w[2];
+    r->w[2] = acc2lo;
+    acc2lo >>= 32;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 30)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 32);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 32;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 30);
+    acc2lo += r->w[3];
+    r->w[3] = acc2lo;
+    acc2lo >>= 32;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 0);
+    acc2lo += r->w[4];
+    r->w[4] = acc2lo;
+    acc2lo = 0;
+    acc2lo += ((acclo >> 4) & (((BignumInt)1 << 28)-1)) * ((BignumDblInt)25 << 0);
+    acclo = acchi + (acclo >> 32);
+    acchi = 0;
+    acc2lo += (acclo & (((BignumInt)1 << 4)-1)) * ((BignumDblInt)25 << 28);
+    acc2lo += r->w[0];
+    r->w[0] = acc2lo;
+    acc2lo >>= 32;
+    acc2lo += ((acclo >> 4) & (((BignumInt)1 << 28)-1)) * ((BignumDblInt)25 << 0);
+    acclo = acchi + (acclo >> 32);
+    acchi = 0;
+    acc2lo += r->w[1];
+    r->w[1] = acc2lo;
+    acc2lo >>= 32;
+    acc2lo += r->w[2];
+    r->w[2] = acc2lo;
+    acc2lo >>= 32;
+    acc2lo += r->w[3];
+    r->w[3] = acc2lo;
+    acc2lo >>= 32;
+    acc2lo += r->w[4];
+    r->w[4] = acc2lo;
+    acc2lo >>= 32;
+#elif BIGNUM_INT_BITS == 16
+    /* ./contrib/make1305.py mul 16 */
+    BignumDblInt tmp;
+    BignumDblInt acclo;
+    BignumDblInt acchi;
+    BignumDblInt acc2lo;
+    acclo = 0;
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    r->w[0] = acclo;
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    r->w[1] = acclo;
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    r->w[2] = acclo;
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    r->w[3] = acclo;
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    r->w[4] = acclo;
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[5]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[5]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    r->w[5] = acclo;
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[6]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[5]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[5]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[6]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    r->w[6] = acclo;
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[7]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[6]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[5]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[5]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[6]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[7]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    r->w[7] = acclo;
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[0]) * (b->w[8]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[7]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[6]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[5]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[5]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[6]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[7]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[8]) * (b->w[0]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    r->w[8] = acclo & (((BignumInt)1 << 2)-1);
+    acc2lo = 0;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 14)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[1]) * (b->w[8]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[7]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[6]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[5]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[5]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[6]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[7]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[8]) * (b->w[1]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 14);
+    acc2lo += r->w[0];
+    r->w[0] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 14)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[2]) * (b->w[8]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[7]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[6]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[5]) * (b->w[5]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[6]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[7]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[8]) * (b->w[2]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 14);
+    acc2lo += r->w[1];
+    r->w[1] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 14)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[3]) * (b->w[8]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[7]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[5]) * (b->w[6]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[6]) * (b->w[5]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[7]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[8]) * (b->w[3]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 14);
+    acc2lo += r->w[2];
+    r->w[2] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 14)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[4]) * (b->w[8]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[5]) * (b->w[7]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[6]) * (b->w[6]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[7]) * (b->w[5]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[8]) * (b->w[4]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 14);
+    acc2lo += r->w[3];
+    r->w[3] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 14)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[5]) * (b->w[8]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[6]) * (b->w[7]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[7]) * (b->w[6]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[8]) * (b->w[5]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 14);
+    acc2lo += r->w[4];
+    r->w[4] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 14)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[6]) * (b->w[8]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[7]) * (b->w[7]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[8]) * (b->w[6]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 14);
+    acc2lo += r->w[5];
+    r->w[5] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 14)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[7]) * (b->w[8]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    tmp = (BignumDblInt)(a->w[8]) * (b->w[7]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 14);
+    acc2lo += r->w[6];
+    r->w[6] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 14)-1)) * ((BignumDblInt)5 << 0);
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    tmp = (BignumDblInt)(a->w[8]) * (b->w[8]);
+    acclo += tmp & BIGNUM_INT_MASK;
+    acchi += tmp >> 16;
+    acc2lo += (acclo & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 14);
+    acc2lo += r->w[7];
+    r->w[7] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += ((acclo >> 2) & (((BignumInt)1 << 2)-1)) * ((BignumDblInt)5 << 0);
+    acc2lo += r->w[8];
+    r->w[8] = acc2lo;
+    acc2lo = 0;
+    acc2lo += ((acclo >> 4) & (((BignumInt)1 << 12)-1)) * ((BignumDblInt)25 << 0);
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    acc2lo += (acclo & (((BignumInt)1 << 4)-1)) * ((BignumDblInt)25 << 12);
+    acc2lo += r->w[0];
+    r->w[0] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += ((acclo >> 4) & (((BignumInt)1 << 12)-1)) * ((BignumDblInt)25 << 0);
+    acclo = acchi + (acclo >> 16);
+    acchi = 0;
+    acc2lo += r->w[1];
+    r->w[1] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += r->w[2];
+    r->w[2] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += r->w[3];
+    r->w[3] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += r->w[4];
+    r->w[4] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += r->w[5];
+    r->w[5] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += r->w[6];
+    r->w[6] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += r->w[7];
+    r->w[7] = acc2lo;
+    acc2lo >>= 16;
+    acc2lo += r->w[8];
+    r->w[8] = acc2lo;
+    acc2lo >>= 16;
+#else
+#error Run contrib/make1305.py again with a different bit count
+#endif
+}
+
+static void bigval_final_reduce(bigval *n)
+{
+#if BIGNUM_INT_BITS == 32
+    /* ./contrib/make1305.py final_reduce 32 */
+    BignumDblInt acclo;
+    acclo = 0;
+    acclo += 5 * ((n->w[4] >> 2) + 1);
+    acclo += n->w[0];
+    acclo >>= 32;
+    acclo += n->w[1];
+    acclo >>= 32;
+    acclo += n->w[2];
+    acclo >>= 32;
+    acclo += n->w[3];
+    acclo >>= 32;
+    acclo += n->w[4];
+    acclo = 5 * (acclo >> 2);
+    acclo += n->w[0];
+    n->w[0] = acclo;
+    acclo >>= 32;
+    acclo += n->w[1];
+    n->w[1] = acclo;
+    acclo >>= 32;
+    acclo += n->w[2];
+    n->w[2] = acclo;
+    acclo >>= 32;
+    acclo += n->w[3];
+    n->w[3] = acclo;
+    acclo >>= 32;
+    acclo += n->w[4];
+    n->w[4] = acclo;
+    acclo >>= 32;
+    n->w[4] &= (1 << 2) - 1;
+#elif BIGNUM_INT_BITS == 16
+    /* ./contrib/make1305.py final_reduce 16 */
+    BignumDblInt acclo;
+    acclo = 0;
+    acclo += 5 * ((n->w[8] >> 2) + 1);
+    acclo += n->w[0];
+    acclo >>= 16;
+    acclo += n->w[1];
+    acclo >>= 16;
+    acclo += n->w[2];
+    acclo >>= 16;
+    acclo += n->w[3];
+    acclo >>= 16;
+    acclo += n->w[4];
+    acclo >>= 16;
+    acclo += n->w[5];
+    acclo >>= 16;
+    acclo += n->w[6];
+    acclo >>= 16;
+    acclo += n->w[7];
+    acclo >>= 16;
+    acclo += n->w[8];
+    acclo = 5 * (acclo >> 2);
+    acclo += n->w[0];
+    n->w[0] = acclo;
+    acclo >>= 16;
+    acclo += n->w[1];
+    n->w[1] = acclo;
+    acclo >>= 16;
+    acclo += n->w[2];
+    n->w[2] = acclo;
+    acclo >>= 16;
+    acclo += n->w[3];
+    n->w[3] = acclo;
+    acclo >>= 16;
+    acclo += n->w[4];
+    n->w[4] = acclo;
+    acclo >>= 16;
+    acclo += n->w[5];
+    n->w[5] = acclo;
+    acclo >>= 16;
+    acclo += n->w[6];
+    n->w[6] = acclo;
+    acclo >>= 16;
+    acclo += n->w[7];
+    n->w[7] = acclo;
+    acclo >>= 16;
+    acclo += n->w[8];
+    n->w[8] = acclo;
+    acclo >>= 16;
+    n->w[8] &= (1 << 2) - 1;
+#else
+#error Run contrib/make1305.py again with a different bit count
+#endif
+}
+
 struct poly1305 {
     unsigned char nonce[16];
-    Bignum modulo;
-    Bignum r;
-    Bignum h;
+    bigval r;
+    bigval h;
 
     /* Buffer in case we get less that a multiple of 16 bytes */
     unsigned char buffer[16];
     int bufferIndex;
 };
 
-static void poly1305_make(struct poly1305 *ctx)
+static void poly1305_init(struct poly1305 *ctx)
 {
-    static const unsigned char p[] = {
-        0x03,
-        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb
-    };
-
-    ctx->modulo = bignum_from_bytes(p, sizeof(p));
-    ctx->r = NULL;
-    ctx->h = NULL;
     memset(ctx->nonce, 0, 16);
     ctx->bufferIndex = 0;
-}
-
-static void poly1305_free(struct poly1305 *ctx)
-{
-    if (ctx->modulo) {
-        freebn(ctx->modulo);
-    }
-    if (ctx->r) {
-        freebn(ctx->r);
-    }
-    if (ctx->h) {
-        freebn(ctx->h);
-    }
-    smemclr(ctx, sizeof(struct poly1305));
+    bigval_clear(&ctx->h);
 }
 
 /* Takes a 256 bit key */
@@ -235,10 +938,7 @@ static void poly1305_key(struct poly1305 *ctx, const unsigned char *key)
     key_copy[4] &= 0xfc;
     key_copy[8] &= 0xfc;
     key_copy[12] &= 0xfc;
-    if (ctx->r) {
-        freebn(ctx->r);
-    }
-    ctx->r = bignum_from_bytes_le(key_copy, 16);
+    bigval_import_le(&ctx->r, key_copy, 16);
     smemclr(key_copy, sizeof(key_copy));
 
     /* Use second 128 bits are the nonce */
@@ -249,21 +949,11 @@ static void poly1305_key(struct poly1305 *ctx, const unsigned char *key)
 static void poly1305_feed_chunk(struct poly1305 *ctx,
                                 const unsigned char *chunk, int len)
 {
-    Bignum tmp, tmp2;
-    Bignum c = bignum_from_bytes_le(chunk, len);
-    tmp = bignum_lshift(One, 8 * len);
-    tmp2 = bigadd(c, tmp);
-    freebn(tmp);
-    freebn(c);
-    if (ctx->h) {
-        tmp = bigadd(ctx->h, tmp2);
-        freebn(tmp2);
-        freebn(ctx->h);
-    } else {
-        tmp = tmp2;
-    }
-    ctx->h = modmul(tmp, ctx->r, ctx->modulo);
-    freebn(tmp);
+    bigval c;
+    bigval_import_le(&c, chunk, len);
+    c.w[len / BIGNUM_INT_BYTES] |= 1 << (8 * (len % BIGNUM_INT_BYTES));
+    bigval_add(&c, &c, &ctx->h);
+    bigval_mul_mod_p(&ctx->h, &c, &ctx->r);
 }
 
 static void poly1305_feed(struct poly1305 *ctx,
@@ -299,21 +989,16 @@ static void poly1305_feed(struct poly1305 *ctx,
 /* Finalise and populate buffer with 16 byte with MAC */
 static void poly1305_finalise(struct poly1305 *ctx, unsigned char *mac)
 {
-    Bignum tmp, tmp2;
-    int i;
+    bigval tmp;
 
     if (ctx->bufferIndex) {
         poly1305_feed_chunk(ctx, ctx->buffer, ctx->bufferIndex);
     }
 
-    tmp = bignum_from_bytes_le(ctx->nonce, 16);
-
-    tmp2 = bigadd(ctx->h, tmp);
-    freebn(tmp);
-    for (i = 0; i < 16; ++i) {
-        mac[i] = bignum_byte(tmp2, i);
-    }
-    freebn(tmp2);
+    bigval_import_le(&tmp, ctx->nonce, 16);
+    bigval_final_reduce(&ctx->h);
+    bigval_add(&tmp, &tmp, &ctx->h);
+    bigval_export_le(&tmp, mac, 16);
 }
 
 /* SSH-2 wrapper */
@@ -351,8 +1036,7 @@ static void poly_start(void *handle)
 
     ctx->mac_initialised = 0;
     memset(ctx->mac_iv, 0, 8);
-    poly1305_free(&ctx->mac);
-    poly1305_make(&ctx->mac);
+    poly1305_init(&ctx->mac);
 }
 
 static void poly_bytes(void *handle, unsigned char const *blk, int len)
@@ -445,7 +1129,7 @@ static void *ccp_make_context(void)
 {
     struct ccp_context *ctx = snew(struct ccp_context);
     if (ctx) {
-        poly1305_make(&ctx->mac);
+        poly1305_init(&ctx->mac);
     }
     return ctx;
 }
@@ -455,7 +1139,7 @@ static void ccp_free_context(void *vctx)
     struct ccp_context *ctx = (struct ccp_context *)vctx;
     smemclr(&ctx->a_cipher, sizeof(ctx->a_cipher));
     smemclr(&ctx->b_cipher, sizeof(ctx->b_cipher));
-    poly1305_free(&ctx->mac);
+    smemclr(&ctx->mac, sizeof(ctx->mac));
     sfree(ctx);
 }