/* -*-c-*-
*
- * $Id: mpbarrett.c,v 1.7 2001/04/19 18:25:26 mdw Exp $
+ * $Id: mpbarrett.c,v 1.8 2001/06/16 13:00:20 mdw Exp $
*
* Barrett modular reduction
*
/*----- Revision history --------------------------------------------------*
*
* $Log: mpbarrett.c,v $
+ * Revision 1.8 2001/06/16 13:00:20 mdw
+ * Use the generic exponentiation functions.
+ *
* Revision 1.7 2001/04/19 18:25:26 mdw
* Use sliding-window exponentiation.
*
#include "mp.h"
#include "mpbarrett.h"
+#include "mpbarrett-exp.h"
/*----- Main code ---------------------------------------------------------*/
* Returns: Result, %$a^e \bmod m$%.
*/
-#define WINSZ 5
-#define TABSZ (1 << (WINSZ - 1))
-
-#define THRESH (((MPW_BITS / WINSZ) << 2) + 1)
-
-static mp *exp_simple(mpbarrett *mb, mp *d, mp *a, mp *e)
-{
- mpscan sc;
- mp *x = MP_ONE;
- mp *spare = (e->f & MP_BURN) ? MP_NEWSEC : MP_NEW;
- unsigned sq = 0;
-
- a = MP_COPY(a);
- mp_rscan(&sc, e);
- if (!MP_RSTEP(&sc))
- goto exit;
- while (!MP_RBIT(&sc))
- MP_RSTEP(&sc);
-
- /* --- Do the main body of the work --- */
-
- for (;;) {
- sq++;
- while (sq) {
- mp *y;
- y = mp_sqr(spare, x);
- y = mpbarrett_reduce(mb, y, y);
- spare = x; x = y;
- sq--;
- }
- {
- mp *y = mp_mul(spare, x, a);
- y = mpbarrett_reduce(mb, y, y);
- spare = x; x = y;
- }
- for (;;) {
- if (!MP_RSTEP(&sc))
- goto done;
- if (MP_RBIT(&sc))
- break;
- sq++;
- }
- }
-
- /* --- Do a final round of squaring --- */
-
-done:
- while (sq) {
- mp *y;
- y = mp_sqr(spare, x);
- y = mpbarrett_reduce(mb, y, y);
- spare = x; x = y;
- sq--;
- }
-
-exit:
- MP_DROP(a);
- if (spare != MP_NEW)
- MP_DROP(spare);
- if (d != MP_NEW)
- MP_DROP(d);
- return (x);
-}
-
mp *mpbarrett_exp(mpbarrett *mb, mp *d, mp *a, mp *e)
{
- mp **tab;
- mp *a2;
- mp *spare = (e->f & MP_BURN) ? MP_NEWSEC : MP_NEW;
mp *x = MP_ONE;
- unsigned i, sq = 0;
- mpscan sc;
-
- /* --- Do we bother? --- */
+ mp *spare = (e->f & MP_BURN) ? MP_NEWSEC : MP_NEW;
MP_SHRINK(e);
- if (MP_LEN(e) == 0)
- goto exit;
- if (MP_LEN(e) < THRESH) {
- x->ref--;
- return (exp_simple(mb, d, a, e));
- }
-
- /* --- Do the precomputation --- */
-
- a2 = mp_sqr(MP_NEW, a);
- a2 = mpbarrett_reduce(mb, a2, a2);
- tab = xmalloc(TABSZ * sizeof(mp *));
- tab[0] = MP_COPY(a);
- for (i = 1; i < TABSZ; i++) {
- mp *x = mp_mul(MP_NEW, tab[i - 1], a2);
- tab[i] = mpbarrett_reduce(mb, x, x);
- }
- mp_drop(a2);
- mp_rscan(&sc, e);
-
- /* --- Skip top-end zero bits --- *
- *
- * If the initial step worked, there must be a set bit somewhere, so keep
- * stepping until I find it.
- */
-
- MP_RSTEP(&sc);
- while (!MP_RBIT(&sc))
- MP_RSTEP(&sc);
-
- /* --- Now for the main work --- */
-
- for (;;) {
- unsigned l = 0;
- unsigned z = 0;
-
- /* --- The next bit is set, so read a window index --- *
- *
- * Reset @i@ to zero and increment @sq@. Then, until either I read
- * @WINSZ@ bits or I run out of bits, scan in a bit: if it's clear, bump
- * the @z@ counter; if it's set, push a set bit into @i@, shift it over
- * by @z@ bits, bump @sq@ by @z + 1@ and clear @z@. By the end of this
- * palaver, @i@ is an index to the precomputed value in @tab@.
- */
-
- i = 0;
- sq++;
- for (;;) {
- l++;
- if (l >= WINSZ || !MP_RSTEP(&sc))
- break;
- if (!MP_RBIT(&sc))
- z++;
- else {
- i = ((i << 1) | 1) << z;
- sq += z + 1;
- z = 0;
- }
- }
-
- /* --- Do the squaring --- *
- *
- * Remember that @sq@ carries over from the zero-skipping stuff below.
- */
-
- while (sq) {
- mp *y;
- y = mp_sqr(spare, x);
- y = mpbarrett_reduce(mb, y, y);
- spare = x; x = y;
- sq--;
- }
-
- /* --- Do the multiply --- */
-
- { mp *y = mp_mul(spare, x, tab[i]); spare = x;
- x = mpbarrett_reduce(mb, y, y); }
-
- /* --- Now grind along through the rest of the bits --- */
-
- sq = z;
- for (;;) {
- if (!MP_RSTEP(&sc))
- goto done;
- if (MP_RBIT(&sc))
- break;
- sq++;
- }
- }
-
- /* --- Do a final round of squaring --- */
-
-done:
- while (sq) {
- mp *y;
- y = mp_sqr(spare, x);
- y = mpbarrett_reduce(mb, y, y);
- spare = x; x = y;
- sq--;
- }
-
- /* --- Done --- */
-
- for (i = 0; i < TABSZ; i++)
- mp_drop(tab[i]);
- xfree(tab);
-exit:
+ if (!MP_LEN(e))
+ ;
+ else if (MP_LEN(e) < EXP_THRESH)
+ EXP_SIMPLE(x, a, e);
+ else
+ EXP_WINDOW(x, a, e);
mp_drop(d);
mp_drop(spare);
return (x);
/* -*-c-*-
*
- * $Id: mpmont-mexp.c,v 1.5 2000/10/08 12:11:22 mdw Exp $
+ * $Id: mpmont-mexp.c,v 1.6 2001/06/16 13:00:20 mdw Exp $
*
* Multiple simultaneous exponentiations
*
/*----- Revision history --------------------------------------------------*
*
* $Log: mpmont-mexp.c,v $
+ * Revision 1.6 2001/06/16 13:00:20 mdw
+ * Use the generic exponentiation functions.
+ *
* Revision 1.5 2000/10/08 12:11:22 mdw
* Use @MP_EQ@ instead of @MP_CMP@.
*
#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
+ * @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)
+mp *mpmont_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;
-
- /* --- 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.
- *
- * If any of the exponents are considered secret then make the accumulator
- * automatically set the secret bit.
- */
-
- {
- 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;
- if (f[i].exp->f & MP_BURN)
- spare = MP_NEWSEC;
- }
- b = 0;
- }
+ mp *a = mp_copy(mm->r);
+ mp *spare;
+ size_t i;
- /* --- 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;
+ spare = MP_NEW;
+ for (i = 0; i < n; i++) {
+ if (f[i].exp->f & MP_BURN) {
+ spare = MP_NEWSEC;
+ break;
}
}
- /* --- Tidy up afterwards --- */
-
- {
- size_t i;
- for (i = 1; i < vn; i++)
- MP_DROP(v[i]);
- if (spare)
- MP_DROP(spare);
- free(v);
- free(s);
- }
-
- if (d != MP_NEW)
- MP_DROP(d);
-
+ EXP_SIMUL(a, f, n);
+ mp_drop(d);
+ mp_drop(spare);
return (a);
}
*
* Arguments: @mpmont *mm@ = pointer to Montgomery reduction context
* @mp *d@ = fake destination
- * @mpmont_factor *f@ = pointer to array of factors
+ * @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, mp_expfactor *f, size_t n)
{
- d = mpmont_mexpr(mm, d, f, n);
+ mp_expfactor *v = xmalloc(sizeof(*v) * n);
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ v[i].base = mpmont_mul(mm, MP_NEW, f[i].base, mm->r2);
+ v[i].exp = f[i].exp;
+ }
+ d = mpmont_mexpr(mm, d, v, n);
+ for (i = 0; i < n; i++)
+ MP_DROP(v[i].base);
+ xfree(v);
d = mpmont_reduce(mm, d, d);
return (d);
}
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;
/* -*-c-*-
*
- * $Id: mpmont.c,v 1.14 2001/02/22 09:04:26 mdw Exp $
+ * $Id: mpmont.c,v 1.15 2001/06/16 13:00:20 mdw Exp $
*
* Montgomery reduction
*
/*----- Revision history --------------------------------------------------*
*
* $Log: mpmont.c,v $
+ * Revision 1.15 2001/06/16 13:00:20 mdw
+ * Use the generic exponentiation functions.
+ *
* Revision 1.14 2001/02/22 09:04:26 mdw
* Cosmetic fix.
*
#include "mp.h"
#include "mpmont.h"
+#include "mpmont-exp.h"
/*----- Tweakables --------------------------------------------------------*/
/* #define MPMONT_DISABLE */
-/*----- Main code ---------------------------------------------------------*/
+/*----- Reduction and multiplication --------------------------------------*/
/* --- @mpmont_create@ --- *
*
#endif
+/*----- Exponentiation ----------------------------------------------------*/
+
/* --- @mpmont_expr@ --- *
*
* Arguments: @mpmont *mm@ = pointer to Montgomery reduction context
* @mp *a@ = base
* @mp *e@ = exponent
*
- * Returns: Result, %$a^e R \bmod m$%.
+ * Returns: Result, %$(a R^{-1})^e R \bmod m$%.
*/
-#define WINSZ 5
-#define TABSZ (1 << (WINSZ - 1))
-
-#define THRESH (((MPW_BITS / WINSZ) << 2) + 1)
-
-static mp *exp_simple(mpmont *mm, mp *d, mp *a, mp *e)
-{
- mpscan sc;
- mp *ar;
- mp *x = MP_COPY(mm->r);
- mp *spare = (e->f & MP_BURN) ? MP_NEWSEC : MP_NEW;
- unsigned sq = 0;
-
- mp_rscan(&sc, e);
- if (!MP_RSTEP(&sc))
- goto exit;
- while (!MP_RBIT(&sc))
- MP_RSTEP(&sc);
-
- /* --- Do the main body of the work --- */
-
- ar = mpmont_mul(mm, MP_NEW, a, mm->r2);
- for (;;) {
- sq++;
- while (sq) {
- mp *y;
- y = mp_sqr(spare, x);
- y = mpmont_reduce(mm, y, y);
- spare = x; x = y;
- sq--;
- }
- { mp *y = mpmont_mul(mm, spare, x, ar); spare = x; x = y; }
- sq = 0;
- for (;;) {
- if (!MP_RSTEP(&sc))
- goto done;
- if (MP_RBIT(&sc))
- break;
- sq++;
- }
- }
-
- /* --- Do a final round of squaring --- */
-
-done:
- while (sq) {
- mp *y;
- y = mp_sqr(spare, x);
- y = mpmont_reduce(mm, y, y);
- spare = x; x = y;
- sq--;
- }
-
- /* --- Done --- */
-
- MP_DROP(ar);
-exit:
- if (spare != MP_NEW)
- MP_DROP(spare);
- if (d != MP_NEW)
- MP_DROP(d);
- return (x);
-}
-
mp *mpmont_expr(mpmont *mm, mp *d, mp *a, mp *e)
{
- mp **tab;
- mp *ar, *a2;
- mp *spare = (e->f & MP_BURN) ? MP_NEWSEC : MP_NEW;
mp *x = MP_COPY(mm->r);
- unsigned i, sq = 0;
- mpscan sc;
-
- /* --- Do we bother? --- */
+ mp *spare = (e->f & MP_BURN) ? MP_NEWSEC : MP_NEW;
MP_SHRINK(e);
if (MP_LEN(e) == 0)
- goto exit;
- if (MP_LEN(e) < THRESH) {
- x->ref--;
- return (exp_simple(mm, d, a, e));
- }
-
- /* --- Do the precomputation --- */
-
- ar = mpmont_mul(mm, MP_NEW, a, mm->r2);
- a2 = mp_sqr(MP_NEW, ar);
- a2 = mpmont_reduce(mm, a2, a2);
- tab = xmalloc(TABSZ * sizeof(mp *));
- tab[0] = ar;
- for (i = 1; i < TABSZ; i++)
- tab[i] = mpmont_mul(mm, MP_NEW, tab[i - 1], a2);
- mp_drop(a2);
- mp_rscan(&sc, e);
-
- /* --- Skip top-end zero bits --- *
- *
- * If the initial step worked, there must be a set bit somewhere, so keep
- * stepping until I find it.
- */
-
- MP_RSTEP(&sc);
- while (!MP_RBIT(&sc))
- MP_RSTEP(&sc);
-
- /* --- Now for the main work --- */
-
- for (;;) {
- unsigned l = 0;
- unsigned z = 0;
-
- /* --- The next bit is set, so read a window index --- *
- *
- * Reset @i@ to zero and increment @sq@. Then, until either I read
- * @WINSZ@ bits or I run out of bits, scan in a bit: if it's clear, bump
- * the @z@ counter; if it's set, push a set bit into @i@, shift it over
- * by @z@ bits, bump @sq@ by @z + 1@ and clear @z@. By the end of this
- * palaver, @i@ is an index to the precomputed value in @tab@.
- */
-
- i = 0;
- sq++;
- for (;;) {
- l++;
- if (l >= WINSZ || !MP_RSTEP(&sc))
- break;
- if (!MP_RBIT(&sc))
- z++;
- else {
- i = ((i << 1) | 1) << z;
- sq += z + 1;
- z = 0;
- }
- }
-
- /* --- Do the squaring --- *
- *
- * Remember that @sq@ carries over from the zero-skipping stuff below.
- */
-
- while (sq) {
- mp *y;
- y = mp_sqr(spare, x);
- y = mpmont_reduce(mm, y, y);
- spare = x; x = y;
- sq--;
- }
-
- /* --- Do the multiply --- */
-
- { mp *y = mpmont_mul(mm, spare, x, tab[i]); spare = x; x = y; }
-
- /* --- Now grind along through the rest of the bits --- */
-
- sq = z;
- for (;;) {
- if (!MP_RSTEP(&sc))
- goto done;
- if (MP_RBIT(&sc))
- break;
- sq++;
- }
- }
-
- /* --- Do a final round of squaring --- */
-
-done:
- while (sq) {
- mp *y;
- y = mp_sqr(spare, x);
- y = mpmont_reduce(mm, y, y);
- spare = x; x = y;
- sq--;
- }
-
- /* --- Done --- */
-
- for (i = 0; i < TABSZ; i++)
- mp_drop(tab[i]);
- xfree(tab);
-exit:
+ ;
+ else if (MP_LEN(e) < EXP_THRESH)
+ EXP_SIMPLE(x, a, e);
+ else
+ EXP_WINDOW(x, a, e);
mp_drop(d);
mp_drop(spare);
return (x);
mp *mpmont_exp(mpmont *mm, mp *d, mp *a, mp *e)
{
- d = mpmont_expr(mm, d, a, e);
+ d = mpmont_mul(mm, d, a, mm->r2);
+ d = mpmont_expr(mm, d, d, e);
d = mpmont_reduce(mm, d, d);
return (d);
}