/* -*-c-*-
*
- * $Id: mpmont-mexp.c,v 1.3 1999/12/10 23:18:39 mdw Exp $
+ * $Id$
*
- * Multiplle simultaneous exponentiations
+ * Multiple simultaneous exponentiations
*
* (c) 1999 Straylight/Edgeware
*/
* MA 02111-1307, USA.
*/
-/*----- Revision history --------------------------------------------------*
- *
- * $Log: mpmont-mexp.c,v $
- * Revision 1.3 1999/12/10 23:18:39 mdw
- * Change interface for suggested destinations.
- *
- * Revision 1.2 1999/11/21 11:35:10 mdw
- * Performance improvement: use @mp_sqr@ and @mpmont_reduce@ instead of
- * @mpmont_mul@ for squaring in exponentiation.
- *
- * Revision 1.1 1999/11/19 13:19:29 mdw
- * Simultaneous exponentiation support.
- *
- */
-
/*----- Header files ------------------------------------------------------*/
#include "mp.h"
#include "mpmont.h"
+#define EXP_WINSZ 3
+#include "mpmont-exp.h"
+
/*----- Main code ---------------------------------------------------------*/
/* --- @mpmont_mexpr@ --- *
*
* Arguments: @mpmont *mm@ = pointer to Montgomery reduction context
* @mp *d@ = fake destination
- * @mpmont_factor *f@ = pointer to array of factors
+ * @const mp_expfactor *f@ = pointer to array of factors
* @size_t n@ = number of factors supplied
*
* Returns: If the bases are %$g_0, g_1, \ldots, g_{n-1}$% and the
* exponents are %$e_0, e_1, \ldots, e_{n-1}$% then the result
* is:
*
- * %$g_0^{e_0} g_1^{e_1} \ldots g_{n-1}^{e_{n-1}} R \bmod m$%
+ * %$g_0^{e_0} g_1^{e_1} \ldots g_{n-1}^{e_{n-1}} \bmod m$%
+ *
+ * except that the %$g_i$% and result are in Montgomery form.
*/
-typedef struct scan {
- size_t len;
- mpw w;
-} scan;
-
-mp *mpmont_mexpr(mpmont *mm, mp *d, mpmont_factor *f, size_t n)
+static mp *mexpr(mpmont *mm, mp *d, mp_expfactor *f, size_t n)
{
- size_t vn = 1 << n;
- mp **v = xmalloc(vn * sizeof(mp *));
- scan *s;
- size_t o;
- unsigned b;
mp *a = MP_COPY(mm->r);
mp *spare = MP_NEW;
+ size_t i;
- /* --- Perform the precomputation --- */
-
- {
- size_t i, j;
- size_t mask;
-
- /* --- Fill in the rest of the array --- *
- *
- * Zero never gets used.
- */
-
- j = 0;
- mask = 0;
- for (i = 1; i < vn; i++) {
-
- /* --- Check for a new bit entering --- *
- *
- * If a bit gets set that wasn't set before, then all the lower bits
- * are zeroes and I've got to introduce a new base into the array.
- */
-
- if ((i & mask) == 0) {
- v[i] = mpmont_mul(mm, MP_NEW, f[j++].base, mm->r2);
- mask = i;
- }
-
- /* --- Otherwise I can get away with a single multiplication --- *
- *
- * In particular, if %$i$% has more than one bit set, then I only need
- * to calculate %$v_i = v_{\mathit{mask}} v_{i - \mathit{mask}}$%.
- * Since both are less than %$i$%, they must have already been
- * computed.
- */
-
- else
- v[i] = mpmont_mul(mm, MP_NEW, v[mask], v[i & ~mask]);
- }
- }
-
- /* --- Set up the bitscanners --- *
- *
- * I must scan the exponents from left to right, which is a shame. It
- * means that I can't use the standard @mpscan@ stuff, in particular.
- */
-
- {
- size_t i;
-
- s = xmalloc(n * sizeof(scan));
- o = 0;
- for (i = 0; i < n; i++) {
- s[i].len = MP_LEN(f[i].exp);
- if (s[i].len > o)
- o = s[i].len;
- }
- b = 0;
- }
-
- /* --- Now do the actual calculation --- */
-
- b = 0;
- for (;;) {
- size_t i;
- size_t j;
- mp *dd;
-
- /* --- If no more bits, get some more --- */
-
- if (!b) {
- if (!o)
- break;
- o--;
- b = MPW_BITS;
- }
-
- /* --- Work out the next index --- */
-
- j = 0;
- b--;
- for (i = 0; i < n; i++) {
- if (o < s[i].len)
- j |= (((f[i].exp->v[o] >> b) & 1) << i);
- }
-
- /* --- Accumulate the result --- */
-
- if (spare) {
- dd = mp_sqr(spare, a);
- dd = mpmont_reduce(mm, dd, dd);
- spare = a;
- a = dd;
- }
-
- if (j) {
- dd = mpmont_mul(mm, spare, a, v[j]);
- spare = a;
- a = dd;
+ for (i = 0; i < n; i++) {
+ mp *t;
+ if (f[i].exp->f & MP_BURN)
+ spare = MP_NEWSEC;
+ if (MP_NEGP(f[i].exp)) {
+ t = mpmont_reduce(mm, f[i].base, f[i].base);
+ t = mp_modinv(t, t, mm->m);
+ f[i].base = mpmont_mul(mm, t, t, mm->r2);
}
}
+ EXP_SIMUL(a, f, n);
+ mp_drop(d);
+ mp_drop(spare);
+ for (i = 0; i < n; i++)
+ MP_DROP(f[i].base);
+ xfree(f);
+ return (a);
+}
- /* --- Tidy up afterwards --- */
+mp *mpmont_mexpr(mpmont *mm, mp *d, const mp_expfactor *f, size_t n)
+{
+ mp_expfactor *ff = xmalloc(n * sizeof(mp_expfactor));
+ size_t i;
- {
- size_t i;
- for (i = 1; i < vn; i++)
- MP_DROP(v[i]);
- if (spare)
- MP_DROP(spare);
- free(v);
- free(s);
+ for (i = 0; i < n; i++) {
+ ff[i].base = MP_COPY(f[i].base);
+ ff[i].exp = f[i].exp;
}
-
- if (d != MP_NEW)
- MP_DROP(d);
-
- return (a);
+ return (mexpr(mm, d, ff, n));
}
/* --- @mpmont_mexp@ --- *
*
* Arguments: @mpmont *mm@ = pointer to Montgomery reduction context
* @mp *d@ = fake destination
- * @mpmont_factor *f@ = pointer to array of factors
+ * @const mp_expfactor *f@ = pointer to array of factors
* @size_t n@ = number of factors supplied
*
* Returns: Product of bases raised to exponents, all mod @m@.
* Use: Convenient interface over @mpmont_mexpr@.
*/
-mp *mpmont_mexp(mpmont *mm, mp *d, mpmont_factor *f, size_t n)
+mp *mpmont_mexp(mpmont *mm, mp *d, const mp_expfactor *f, size_t n)
{
- d = mpmont_mexpr(mm, d, f, n);
- d = mpmont_reduce(mm, d, d);
- return (d);
+ mp_expfactor *ff = xmalloc(n * sizeof(mp_expfactor));
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ ff[i].base = mpmont_mul(mm, MP_NEW, f[i].base, mm->r2);
+ ff[i].exp = f[i].exp;
+ }
+ d = mexpr(mm, d, ff, n);
+ return (mpmont_reduce(mm, d, d));
}
/*----- Test rig ----------------------------------------------------------*/
static int verify(size_t n, dstr *v)
{
mp *m = *(mp **)v[0].buf;
- mpmont_factor *f = xmalloc(n * sizeof(*f));
+ mp_expfactor *f = xmalloc(n * sizeof(*f));
mp *r, *rr;
size_t i, j;
mpmont mm;
rr = *(mp **)v[j].buf;
mpmont_create(&mm, m);
r = mpmont_mexp(&mm, MP_NEW, f, n);
- if (MP_CMP(r, !=, rr)) {
+ if (!MP_EQ(r, rr)) {
fputs("\n*** mexp failed\n", stderr);
fputs("m = ", stderr); mp_writefile(m, stderr, 10);
for (i = 0; i < n; i++) {