18 #define DEBUG // GCC 4.0 bug if NDEBUG and Optimize > 1
20 #include "runtime.hpp"
21 #include "algebra.hpp"
29 namespace STL = STL_NAMESPACE;
35 const Integer& AbstractGroup::Double(
const Element &a)
const
40 const Integer& AbstractGroup::Subtract(
const Element &a,
const Element &b)
const
44 return Add(a1, Inverse(b));
47 Integer& AbstractGroup::Accumulate(Element &a,
const Element &b)
const
52 Integer& AbstractGroup::Reduce(Element &a,
const Element &b)
const
54 return a = Subtract(a, b);
57 const Integer& AbstractRing::Square(
const Element &a)
const
59 return Multiply(a, a);
63 const Integer& AbstractRing::Divide(
const Element &a,
const Element &b)
const
67 return Multiply(a1, MultiplicativeInverse(b));
71 const Integer& AbstractEuclideanDomain::Mod(
const Element &a,
72 const Element &b)
const
75 DivisionAlgorithm(result, q, a, b);
79 const Integer& AbstractEuclideanDomain::Gcd(
const Element &a,
80 const Element &b)
const
82 STL::vector<Element> g(3);
85 unsigned int i0=0, i1=1, i2=2;
87 while (!Equal(g[i1], this->Identity()))
89 g[i2] = Mod(g[i0], g[i1]);
90 unsigned int t = i0; i0 = i1; i1 = i2; i2 = t;
93 return result = g[i0];
97 Integer AbstractGroup::ScalarMultiply(
const Element &base,
98 const Integer &exponent)
const
101 SimultaneousMultiply(&result, base, &exponent, 1);
106 Integer AbstractGroup::CascadeScalarMultiply(
const Element &x,
107 const Integer &e1,
const Element &y,
const Integer &e2)
const
109 const unsigned expLen = max(e1.BitCount(), e2.BitCount());
113 const unsigned w = (expLen <= 46 ? 1 : (expLen <= 260 ? 2 : 3));
114 const unsigned tableSize = 1<<w;
115 STL::vector<Element> powerTable(tableSize << w);
118 powerTable[tableSize] = y;
120 powerTable[3] = Add(x,y);
123 powerTable[2] = Double(x);
124 powerTable[2*tableSize] = Double(y);
128 for (i=3; i<tableSize; i+=2)
129 powerTable[i] = Add(powerTable[i-2], powerTable[2]);
130 for (i=1; i<tableSize; i+=2)
131 for (j=i+tableSize; j<(tableSize<<w); j+=tableSize)
132 powerTable[j] = Add(powerTable[j-tableSize], y);
134 for (i=3*tableSize; i<(tableSize<<w); i+=2*tableSize)
135 powerTable[i] = Add(powerTable[i-2*tableSize],
136 powerTable[2*tableSize]);
137 for (i=tableSize; i<(tableSize<<w); i+=2*tableSize)
138 for (j=i+2; j<i+tableSize; j+=2)
139 powerTable[j] = Add(powerTable[j-1], x);
143 unsigned power1 = 0, power2 = 0, prevPosition = expLen-1;
144 bool firstTime =
true;
146 for (
int i = expLen-1; i>=0; i--)
148 power1 = 2*power1 + e1.GetBit(i);
149 power2 = 2*power2 + e2.GetBit(i);
151 if (i==0 || 2*power1 >= tableSize || 2*power2 >= tableSize)
153 unsigned squaresBefore = prevPosition-
i;
154 unsigned squaresAfter = 0;
156 while ((power1 || power2) && power1%2 == 0 && power2%2==0)
165 result = powerTable[(power2<<w) + power1];
170 while (squaresBefore--)
171 result = Double(result);
172 if (power1 || power2)
173 Accumulate(result, powerTable[(power2<<w) + power1]);
175 while (squaresAfter--)
176 result = Double(result);
187 unsigned int windowSizeIn=0)
188 : exp(expIn), windowModulus(Integer::One()), windowSize(windowSizeIn),
189 windowBegin(0), fastNegate(fastNegateIn), firstTime(
true),
194 unsigned int expLen = exp.BitCount();
195 windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 :
196 (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 :
197 (expLen <= 1434 ? 6 : 7)))));
199 windowModulus <<= windowSize;
202 void FindNextWindow()
204 unsigned int expLen = exp.WordCount() * WORD_BITS;
205 unsigned int skipCount = firstTime ? 0 : windowSize;
207 while (!exp.GetBit(skipCount))
209 if (skipCount >= expLen)
218 windowBegin += skipCount;
219 expWindow = exp % (1 << windowSize);
221 if (fastNegate && exp.GetBit(windowSize))
224 expWindow = (1 << windowSize) - expWindow;
225 exp += windowModulus;
232 unsigned int windowSize, windowBegin, expWindow;
233 bool fastNegate, negateNext, firstTime, finished;
237 void AbstractGroup::SimultaneousMultiply(
Integer *results,
const Integer &base,
238 const Integer *expBegin,
unsigned int expCount)
const
240 STL::vector<STL::vector<Element> > buckets(expCount);
241 STL::vector<WindowSlider> exponents;
242 exponents.reserve(expCount);
245 for (i=0; i<expCount; i++)
247 exponents.push_back(
WindowSlider(*expBegin++, InversionIsFast(), 0));
248 exponents[
i].FindNextWindow();
249 buckets[
i].resize(1<<(exponents[i].windowSize-1), Identity());
252 unsigned int expBitPosition = 0;
259 for (i=0; i<expCount; i++)
261 if (!exponents[i].finished && expBitPosition ==
262 exponents[i].windowBegin)
264 Element &
bucket = buckets[
i][exponents[
i].expWindow/2];
265 if (exponents[i].negateNext)
266 Accumulate(bucket, Inverse(g));
268 Accumulate(bucket, g);
269 exponents[
i].FindNextWindow();
271 notDone = notDone || !exponents[
i].finished;
281 for (i=0; i<expCount; i++)
283 Element &r = *results++;
284 r = buckets[
i][buckets[
i].size()-1];
285 if (buckets[i].
size() > 1)
287 for (
size_t j = buckets[i].
size()-2; j >= 1; j--)
289 Accumulate(buckets[i][j], buckets[i][j+1]);
290 Accumulate(r, buckets[i][j]);
292 Accumulate(buckets[i][0], buckets[i][1]);
293 r = Add(Double(r), buckets[i][0]);
298 Integer AbstractRing::Exponentiate(
const Element &base,
299 const Integer &exponent)
const
302 SimultaneousExponentiate(&result, base, &exponent, 1);
307 Integer AbstractRing::CascadeExponentiate(
const Element &x,
308 const Integer &e1,
const Element &y,
const Integer &e2)
const
310 return MultiplicativeGroup().AbstractGroup::CascadeScalarMultiply(
315 void AbstractRing::SimultaneousExponentiate(Integer *results,
317 const Integer *exponents,
unsigned int expCount)
const
319 MultiplicativeGroup().AbstractGroup::SimultaneousMultiply(results, base,
320 exponents, expCount);
327 #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION