diff --git a/zmod.c b/zmod.c index ed00390..3c889ac 100644 --- a/zmod.c +++ b/zmod.c @@ -480,7 +480,7 @@ zmod6(ZVALUE z1, ZVALUE *res) * slightly faster. */ void -zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) +zpowermod(ZVALUE z1, ZVALUE z2, ZVALUE z3, ZVALUE *res) { HALF *hp; /* pointer to current word of the power */ REDC *rp; /* REDC information to be used */ @@ -488,11 +488,12 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) ZVALUE ans, temp; /* calculation values */ ZVALUE modpow; /* current small power */ ZVALUE lowpowers[POWNUMS]; /* low powers */ - ZVALUE z1; + ZVALUE ztmp; int curshift; /* shift value for word of power */ HALF curhalf; /* current word of power */ unsigned int curpow; /* current low power */ unsigned int curbit; /* current bit of low power */ + BOOL free_z1; /* TRUE => need to free z1 */ int i; if (zisneg(z3) || ziszero(z3)) { @@ -508,7 +509,7 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) /* * Check easy cases first. */ - if ((ziszero(z1_arg) && !ziszero(z2)) || zisunit(z3)) { + if ((ziszero(z1) && !ziszero(z2)) || zisunit(z3)) { /* 0^(non_zero) or x^y mod 1 always produces zero */ *res = _zero_; return; @@ -518,13 +519,13 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) return; } if (zistwo(z3)) { /* mod 2 */ - if (zisodd(z1_arg)) + if (zisodd(z1)) *res = _one_; else *res = _zero_; return; } - if (zisunit(z1_arg) && (!z1_arg.sign || ziseven(z2))) { + if (zisunit(z1) && (!z1.sign || ziseven(z2))) { /* 1^x or (-1)^(2x) */ *res = _one_; return; @@ -534,18 +535,25 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) * Normalize the number being raised to be non-negative and to lie * within the modulo range. Then check for zero or one specially. */ - if (zisneg(z1_arg) || zrel(z1_arg, z3) >= 0) { - zmod(z1_arg, z3, &z1, 0); - } else { - zcopy(z1_arg, &z1); + ztmp.len = 0; + free_z1 = FALSE; + if (zisneg(z1) || zrel(z1, z3) >= 0) { + zmod(z1, z3, &ztmp, 0); + zfree(z1); + z1 = ztmp; + free_z1 = TRUE; } if (ziszero(z1)) { zfree(z1); + if (ztmp.len) + zfree(ztmp); *res = _zero_; return; } if (zisone(z1)) { zfree(z1); + if (ztmp.len) + zfree(ztmp); *res = _one_; return; } @@ -573,7 +581,7 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) pp->v = NULL; } lowpowers[0] = _one_; - zcopy(z1, &lowpowers[1]); + lowpowers[1] = z1; ans = _one_; hp = &z2.v[z2.len - 1]; @@ -596,10 +604,12 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) * future use. */ if (pp->v == NULL) { - if (curpow & 0x1) + if (curpow & 0x1) { zcopy(z1, &modpow); - else + free_z1 = FALSE; + } else { modpow = _one_; + } for (curbit = 0x2; curbit <= curpow; @@ -664,11 +674,12 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) } } - for (pp = &lowpowers[1]; pp <= &lowpowers[POWNUMS-1]; pp++) { + for (pp = &lowpowers[2]; pp <= &lowpowers[POWNUMS-1]; pp++) { zfree(*pp); } *res = ans; - zfree(z1); + if (ztmp.len) + zfree(ztmp); return; } @@ -685,7 +696,9 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) powermodredc = zredcalloc(z3); rp = powermodredc; zredcencode(rp, z1, &temp); - zfree(z1); + if (free_z1 == TRUE) { + zfree(z1); + } zredcpower(rp, temp, z2, &z1); zfree(temp); zredcdecode(rp, z1, res); @@ -702,7 +715,7 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) pp->v = NULL; } lowpowers[0] = _one_; - zcopy(z1, &lowpowers[1]); + lowpowers[1] = z1; ans = _one_; hp = &z2.v[z2.len - 1]; @@ -724,10 +737,12 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) * calculate it and remember it in the table for future use. */ if (pp->v == NULL) { - if (curpow & 0x1) + if (curpow & 0x1) { zcopy(z1, &modpow); - else + free_z1 = FALSE; + } else { modpow = _one_; + } for (curbit = 0x2; curbit <= curpow; curbit *= 2) { pp = &lowpowers[curbit]; @@ -744,7 +759,9 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) } } pp = &lowpowers[curpow]; - zfree(*pp); + if (pp->v != NULL) { + zfree(*pp); + } *pp = modpow; } @@ -783,12 +800,15 @@ zpowermod(ZVALUE z1_arg, ZVALUE z2, ZVALUE z3, ZVALUE *res) } } - for (pp = &lowpowers[1]; pp <= &lowpowers[POWNUMS-1]; pp++) { + for (pp = &lowpowers[2]; pp <= &lowpowers[POWNUMS-1]; pp++) { zfree(*pp); } *res = ans; - zfree(z1); - return; + if (ztmp.len) + zfree(ztmp); + if (free_z1 == TRUE) { + zfree(z1); + } } /* @@ -1129,7 +1149,8 @@ zredcdecode(REDC *rp, ZVALUE z1, ZVALUE *res) if (ztop.len) { zadd(*res, ztop, &tmp1); zfree(*res); - zfree(ztmp); + if (ztmp.len) + zfree(ztmp); *res = tmp1; } @@ -1497,13 +1518,15 @@ zredcsquare(REDC *rp, ZVALUE z1, ZVALUE *res) } if (ziszero(z1)) { *res = _zero_; - zfree(ztmp); + if (ztmp.len) + zfree(ztmp); return; } if ((z1.len == rp->one.len) && (z1.v[0] == rp->one.v[0]) && (zcmp(z1, rp->one) == 0)) { zcopy(z1, res); - zfree(ztmp); + if (ztmp.len) + zfree(ztmp); return; } @@ -1518,7 +1541,8 @@ zredcsquare(REDC *rp, ZVALUE z1, ZVALUE *res) zsquare(z1, &tmp); zredcdecode(rp, tmp, res); zfree(tmp); - zfree(ztmp); + if (ztmp.len) + zfree(ztmp); return; } modlen = rp->mod.len; @@ -1623,7 +1647,8 @@ zredcsquare(REDC *rp, ZVALUE z1, ZVALUE *res) } res->len = len; if (zrel(*res, rp->mod) < 0) { - zfree(ztmp); + if (ztmp.len) + zfree(ztmp); return; } } @@ -1646,7 +1671,8 @@ zredcsquare(REDC *rp, ZVALUE z1, ZVALUE *res) len--; } res->len = len; - zfree(ztmp); + if (ztmp.len) + zfree(ztmp); } @@ -1705,7 +1731,8 @@ zredcpower(REDC *rp, ZVALUE z1, ZVALUE z2, ZVALUE *res) *res = _one_; else *res = _zero_; - zfree(ztmp); + if (ztmp.len) + zfree(ztmp); return; } if (zcmp(z1, rp->one) == 0) { @@ -1713,7 +1740,8 @@ zredcpower(REDC *rp, ZVALUE z1, ZVALUE z2, ZVALUE *res) zsub(rp->mod, rp->one, res); else zcopy(rp->one, res); - zfree(ztmp); + if (ztmp.len) + zfree(ztmp); return; } @@ -1727,12 +1755,14 @@ zredcpower(REDC *rp, ZVALUE z1, ZVALUE z2, ZVALUE *res) if (zcmp(z1, temp) == 0) { if (zisodd(z2) ^ sign) { *res = temp; - zfree(ztmp); + if (ztmp.len) + zfree(ztmp); return; } zfree(temp); zcopy(rp->one, res); - zfree(ztmp); + if (ztmp.len) + zfree(ztmp); return; } zfree(temp); @@ -1820,8 +1850,7 @@ zredcpower(REDC *rp, ZVALUE z1, ZVALUE z2, ZVALUE *res) } for (pp = lowpowers; pp < &lowpowers[POWNUMS]; pp++) { - if (pp->len) - freeh(pp->v); + zfree(*pp); } if (sign && !ziszero(ans)) { zsub(rp->mod, ans, res); @@ -1829,7 +1858,8 @@ zredcpower(REDC *rp, ZVALUE z1, ZVALUE z2, ZVALUE *res) } else { *res = ans; } - zfree(ztmp); + if (ztmp.len) + zfree(ztmp); }