Line | Count | Source (jump to first uncovered line) |
1 | | // ecp.cpp - originally written and placed in the public domain by Wei Dai |
2 | | |
3 | | #include "pch.h" |
4 | | |
5 | | #ifndef CRYPTOPP_IMPORTS |
6 | | |
7 | | #include "ecp.h" |
8 | | #include "asn.h" |
9 | | #include "integer.h" |
10 | | #include "nbtheory.h" |
11 | | #include "modarith.h" |
12 | | #include "filters.h" |
13 | | #include "algebra.cpp" |
14 | | |
15 | | ANONYMOUS_NAMESPACE_BEGIN |
16 | | |
17 | | using CryptoPP::ECP; |
18 | | using CryptoPP::Integer; |
19 | | using CryptoPP::ModularArithmetic; |
20 | | |
21 | | #if defined(HAVE_GCC_INIT_PRIORITY) |
22 | | #define INIT_ATTRIBUTE __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 50))) |
23 | | const ECP::Point g_identity INIT_ATTRIBUTE = ECP::Point(); |
24 | | #elif defined(HAVE_MSC_INIT_PRIORITY) |
25 | | #pragma warning(disable: 4075) |
26 | | #pragma init_seg(".CRT$XCU") |
27 | | const ECP::Point g_identity; |
28 | | #pragma warning(default: 4075) |
29 | | #elif defined(HAVE_XLC_INIT_PRIORITY) |
30 | | #pragma priority(290) |
31 | | const ECP::Point g_identity; |
32 | | #endif |
33 | | |
34 | | inline ECP::Point ToMontgomery(const ModularArithmetic &mr, const ECP::Point &P) |
35 | 0 | { |
36 | 0 | return P.identity ? P : ECP::Point(mr.ConvertIn(P.x), mr.ConvertIn(P.y)); |
37 | 0 | } |
38 | | |
39 | | inline ECP::Point FromMontgomery(const ModularArithmetic &mr, const ECP::Point &P) |
40 | 0 | { |
41 | 0 | return P.identity ? P : ECP::Point(mr.ConvertOut(P.x), mr.ConvertOut(P.y)); |
42 | 0 | } |
43 | | |
44 | | inline Integer IdentityToInteger(bool val) |
45 | 0 | { |
46 | 0 | return val ? Integer::One() : Integer::Zero(); |
47 | 0 | } |
48 | | |
49 | | struct ProjectivePoint |
50 | | { |
51 | 0 | ProjectivePoint() {} |
52 | | ProjectivePoint(const Integer &x, const Integer &y, const Integer &z) |
53 | 0 | : x(x), y(y), z(z) {} |
54 | | |
55 | | Integer x, y, z; |
56 | | }; |
57 | | |
58 | | ANONYMOUS_NAMESPACE_END |
59 | | |
60 | | NAMESPACE_BEGIN(CryptoPP) |
61 | | |
62 | | ECP::ECP(const ECP &ecp, bool convertToMontgomeryRepresentation) |
63 | 27.1k | { |
64 | 27.1k | if (convertToMontgomeryRepresentation && !ecp.GetField().IsMontgomeryRepresentation()) |
65 | 27.1k | { |
66 | 27.1k | m_fieldPtr.reset(new MontgomeryRepresentation(ecp.GetField().GetModulus())); |
67 | 27.1k | m_a = GetField().ConvertIn(ecp.m_a); |
68 | 27.1k | m_b = GetField().ConvertIn(ecp.m_b); |
69 | 27.1k | } |
70 | 0 | else |
71 | 0 | operator=(ecp); |
72 | 27.1k | } |
73 | | |
74 | | ECP::ECP(BufferedTransformation &bt) |
75 | | : m_fieldPtr(new Field(bt)) |
76 | 0 | { |
77 | 0 | BERSequenceDecoder seq(bt); |
78 | 0 | GetField().BERDecodeElement(seq, m_a); |
79 | 0 | GetField().BERDecodeElement(seq, m_b); |
80 | | // skip optional seed |
81 | 0 | if (!seq.EndReached()) |
82 | 0 | { |
83 | 0 | SecByteBlock seed; |
84 | 0 | unsigned int unused; |
85 | 0 | BERDecodeBitString(seq, seed, unused); |
86 | 0 | } |
87 | 0 | seq.MessageEnd(); |
88 | 0 | } |
89 | | |
90 | | void ECP::DEREncode(BufferedTransformation &bt) const |
91 | 0 | { |
92 | 0 | GetField().DEREncode(bt); |
93 | 0 | DERSequenceEncoder seq(bt); |
94 | 0 | GetField().DEREncodeElement(seq, m_a); |
95 | 0 | GetField().DEREncodeElement(seq, m_b); |
96 | 0 | seq.MessageEnd(); |
97 | 0 | } |
98 | | |
99 | | bool ECP::DecodePoint(ECP::Point &P, const byte *encodedPoint, size_t encodedPointLen) const |
100 | 0 | { |
101 | 0 | StringStore store(encodedPoint, encodedPointLen); |
102 | 0 | return DecodePoint(P, store, encodedPointLen); |
103 | 0 | } |
104 | | |
105 | | bool ECP::DecodePoint(ECP::Point &P, BufferedTransformation &bt, size_t encodedPointLen) const |
106 | 27.1k | { |
107 | 27.1k | byte type; |
108 | 27.1k | if (encodedPointLen < 1 || !bt.Get(type)) |
109 | 0 | return false; |
110 | | |
111 | 27.1k | switch (type) |
112 | 27.1k | { |
113 | 0 | case 0: |
114 | 0 | P.identity = true; |
115 | 0 | return true; |
116 | 0 | case 2: |
117 | 0 | case 3: |
118 | 0 | { |
119 | 0 | if (encodedPointLen != EncodedPointSize(true)) |
120 | 0 | return false; |
121 | | |
122 | | // Check for p is prime due to GH #1249 |
123 | 0 | const Integer p = FieldSize(); |
124 | 0 | CRYPTOPP_ASSERT(IsPrime(p)); |
125 | 0 | if (!IsPrime(p)) |
126 | 0 | return false; |
127 | | |
128 | 0 | P.identity = false; |
129 | 0 | P.x.Decode(bt, GetField().MaxElementByteLength()); |
130 | 0 | P.y = ((P.x*P.x+m_a)*P.x+m_b) % p; |
131 | |
|
132 | 0 | if (Jacobi(P.y, p) !=1) |
133 | 0 | return false; |
134 | | |
135 | | // Callers must ensure p is prime, GH #1249 |
136 | 0 | P.y = ModularSquareRoot(P.y, p); |
137 | |
|
138 | 0 | if ((type & 1) != P.y.GetBit(0)) |
139 | 0 | P.y = p-P.y; |
140 | |
|
141 | 0 | return true; |
142 | 0 | } |
143 | 27.1k | case 4: |
144 | 27.1k | { |
145 | 27.1k | if (encodedPointLen != EncodedPointSize(false)) |
146 | 0 | return false; |
147 | | |
148 | 27.1k | unsigned int len = GetField().MaxElementByteLength(); |
149 | 27.1k | P.identity = false; |
150 | 27.1k | P.x.Decode(bt, len); |
151 | 27.1k | P.y.Decode(bt, len); |
152 | 27.1k | return true; |
153 | 27.1k | } |
154 | 0 | default: |
155 | 0 | return false; |
156 | 27.1k | } |
157 | 27.1k | } |
158 | | |
159 | | void ECP::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const |
160 | 0 | { |
161 | 0 | if (P.identity) |
162 | 0 | NullStore().TransferTo(bt, EncodedPointSize(compressed)); |
163 | 0 | else if (compressed) |
164 | 0 | { |
165 | 0 | bt.Put((byte)(2U + P.y.GetBit(0))); |
166 | 0 | P.x.Encode(bt, GetField().MaxElementByteLength()); |
167 | 0 | } |
168 | 0 | else |
169 | 0 | { |
170 | 0 | unsigned int len = GetField().MaxElementByteLength(); |
171 | 0 | bt.Put(4U); // uncompressed |
172 | 0 | P.x.Encode(bt, len); |
173 | 0 | P.y.Encode(bt, len); |
174 | 0 | } |
175 | 0 | } |
176 | | |
177 | | void ECP::EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const |
178 | 0 | { |
179 | 0 | ArraySink sink(encodedPoint, EncodedPointSize(compressed)); |
180 | 0 | EncodePoint(sink, P, compressed); |
181 | 0 | CRYPTOPP_ASSERT(sink.TotalPutLength() == EncodedPointSize(compressed)); |
182 | 0 | } |
183 | | |
184 | | ECP::Point ECP::BERDecodePoint(BufferedTransformation &bt) const |
185 | 0 | { |
186 | 0 | SecByteBlock str; |
187 | 0 | BERDecodeOctetString(bt, str); |
188 | 0 | Point P; |
189 | 0 | if (!DecodePoint(P, str, str.size())) |
190 | 0 | BERDecodeError(); |
191 | 0 | return P; |
192 | 0 | } |
193 | | |
194 | | void ECP::DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const |
195 | 0 | { |
196 | 0 | SecByteBlock str(EncodedPointSize(compressed)); |
197 | 0 | EncodePoint(str, P, compressed); |
198 | 0 | DEREncodeOctetString(bt, str); |
199 | 0 | } |
200 | | |
201 | | bool ECP::ValidateParameters(RandomNumberGenerator &rng, unsigned int level) const |
202 | 0 | { |
203 | 0 | Integer p = FieldSize(); |
204 | |
|
205 | 0 | bool pass = p.IsOdd(); |
206 | 0 | pass = pass && !m_a.IsNegative() && m_a<p && !m_b.IsNegative() && m_b<p; |
207 | |
|
208 | 0 | if (level >= 1) |
209 | 0 | pass = pass && ((4*m_a*m_a*m_a+27*m_b*m_b)%p).IsPositive(); |
210 | |
|
211 | 0 | if (level >= 2) |
212 | 0 | pass = pass && VerifyPrime(rng, p); |
213 | |
|
214 | 0 | return pass; |
215 | 0 | } |
216 | | |
217 | | bool ECP::VerifyPoint(const Point &P) const |
218 | 0 | { |
219 | 0 | const FieldElement &x = P.x, &y = P.y; |
220 | 0 | Integer p = FieldSize(); |
221 | 0 | return P.identity || |
222 | 0 | (!x.IsNegative() && x<p && !y.IsNegative() && y<p |
223 | 0 | && !(((x*x+m_a)*x+m_b-y*y)%p)); |
224 | 0 | } |
225 | | |
226 | | bool ECP::Equal(const Point &P, const Point &Q) const |
227 | 0 | { |
228 | 0 | if (P.identity && Q.identity) |
229 | 0 | return true; |
230 | | |
231 | 0 | if (P.identity && !Q.identity) |
232 | 0 | return false; |
233 | | |
234 | 0 | if (!P.identity && Q.identity) |
235 | 0 | return false; |
236 | | |
237 | 0 | return (GetField().Equal(P.x,Q.x) && GetField().Equal(P.y,Q.y)); |
238 | 0 | } |
239 | | |
240 | | const ECP::Point& ECP::Identity() const |
241 | 0 | { |
242 | 0 | #if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY) || defined(HAVE_XLC_INIT_PRIORITY) |
243 | 0 | return g_identity; |
244 | | #elif defined(CRYPTOPP_CXX11_STATIC_INIT) |
245 | | static const ECP::Point g_identity; |
246 | | return g_identity; |
247 | | #else |
248 | | return Singleton<Point>().Ref(); |
249 | | #endif |
250 | 0 | } |
251 | | |
252 | | const ECP::Point& ECP::Inverse(const Point &P) const |
253 | 0 | { |
254 | 0 | if (P.identity) |
255 | 0 | return P; |
256 | 0 | else |
257 | 0 | { |
258 | 0 | m_R.identity = false; |
259 | 0 | m_R.x = P.x; |
260 | 0 | m_R.y = GetField().Inverse(P.y); |
261 | 0 | return m_R; |
262 | 0 | } |
263 | 0 | } |
264 | | |
265 | | const ECP::Point& ECP::Add(const Point &P, const Point &Q) const |
266 | 0 | { |
267 | 0 | if (P.identity) return Q; |
268 | 0 | if (Q.identity) return P; |
269 | 0 | if (GetField().Equal(P.x, Q.x)) |
270 | 0 | return GetField().Equal(P.y, Q.y) ? Double(P) : Identity(); |
271 | | |
272 | 0 | FieldElement t = GetField().Subtract(Q.y, P.y); |
273 | 0 | t = GetField().Divide(t, GetField().Subtract(Q.x, P.x)); |
274 | 0 | FieldElement x = GetField().Subtract(GetField().Subtract(GetField().Square(t), P.x), Q.x); |
275 | 0 | m_R.y = GetField().Subtract(GetField().Multiply(t, GetField().Subtract(P.x, x)), P.y); |
276 | |
|
277 | 0 | m_R.x.swap(x); |
278 | 0 | m_R.identity = false; |
279 | 0 | return m_R; |
280 | 0 | } |
281 | | |
282 | | const ECP::Point& ECP::Double(const Point &P) const |
283 | 0 | { |
284 | 0 | if (P.identity || P.y==GetField().Identity()) return Identity(); |
285 | | |
286 | 0 | FieldElement t = GetField().Square(P.x); |
287 | 0 | t = GetField().Add(GetField().Add(GetField().Double(t), t), m_a); |
288 | 0 | t = GetField().Divide(t, GetField().Double(P.y)); |
289 | 0 | FieldElement x = GetField().Subtract(GetField().Subtract(GetField().Square(t), P.x), P.x); |
290 | 0 | m_R.y = GetField().Subtract(GetField().Multiply(t, GetField().Subtract(P.x, x)), P.y); |
291 | |
|
292 | 0 | m_R.x.swap(x); |
293 | 0 | m_R.identity = false; |
294 | 0 | return m_R; |
295 | 0 | } |
296 | | |
297 | | template <class T, class Iterator> void ParallelInvert(const AbstractRing<T> &ring, Iterator begin, Iterator end) |
298 | 0 | { |
299 | 0 | size_t n = end-begin; |
300 | 0 | if (n == 1) |
301 | 0 | *begin = ring.MultiplicativeInverse(*begin); |
302 | 0 | else if (n > 1) |
303 | 0 | { |
304 | 0 | std::vector<T> vec((n+1)/2); |
305 | 0 | unsigned int i; |
306 | 0 | Iterator it; |
307 | |
|
308 | 0 | for (i=0, it=begin; i<n/2; i++, it+=2) |
309 | 0 | vec[i] = ring.Multiply(*it, *(it+1)); |
310 | 0 | if (n%2 == 1) |
311 | 0 | vec[n/2] = *it; |
312 | |
|
313 | 0 | ParallelInvert(ring, vec.begin(), vec.end()); |
314 | |
|
315 | 0 | for (i=0, it=begin; i<n/2; i++, it+=2) |
316 | 0 | { |
317 | 0 | if (!vec[i]) |
318 | 0 | { |
319 | 0 | *it = ring.MultiplicativeInverse(*it); |
320 | 0 | *(it+1) = ring.MultiplicativeInverse(*(it+1)); |
321 | 0 | } |
322 | 0 | else |
323 | 0 | { |
324 | 0 | std::swap(*it, *(it+1)); |
325 | 0 | *it = ring.Multiply(*it, vec[i]); |
326 | 0 | *(it+1) = ring.Multiply(*(it+1), vec[i]); |
327 | 0 | } |
328 | 0 | } |
329 | 0 | if (n%2 == 1) |
330 | 0 | *it = vec[n/2]; |
331 | 0 | } |
332 | 0 | } Unexecuted instantiation: void CryptoPP::ParallelInvert<CryptoPP::Integer, CryptoPP::ZIterator>(CryptoPP::AbstractRing<CryptoPP::Integer> const&, CryptoPP::ZIterator, CryptoPP::ZIterator) Unexecuted instantiation: void CryptoPP::ParallelInvert<CryptoPP::Integer, std::__1::__wrap_iter<CryptoPP::Integer*> >(CryptoPP::AbstractRing<CryptoPP::Integer> const&, std::__1::__wrap_iter<CryptoPP::Integer*>, std::__1::__wrap_iter<CryptoPP::Integer*>) |
333 | | |
334 | | class ProjectiveDoubling |
335 | | { |
336 | | public: |
337 | | ProjectiveDoubling(const ModularArithmetic &m_mr, const Integer &m_a, const Integer &m_b, const ECPPoint &Q) |
338 | | : mr(m_mr) |
339 | 0 | { |
340 | 0 | CRYPTOPP_UNUSED(m_b); |
341 | 0 | if (Q.identity) |
342 | 0 | { |
343 | 0 | sixteenY4 = P.x = P.y = mr.MultiplicativeIdentity(); |
344 | 0 | aZ4 = P.z = mr.Identity(); |
345 | 0 | } |
346 | 0 | else |
347 | 0 | { |
348 | 0 | P.x = Q.x; |
349 | 0 | P.y = Q.y; |
350 | 0 | sixteenY4 = P.z = mr.MultiplicativeIdentity(); |
351 | 0 | aZ4 = m_a; |
352 | 0 | } |
353 | 0 | } |
354 | | |
355 | | void Double() |
356 | 0 | { |
357 | 0 | twoY = mr.Double(P.y); |
358 | 0 | P.z = mr.Multiply(P.z, twoY); |
359 | 0 | fourY2 = mr.Square(twoY); |
360 | 0 | S = mr.Multiply(fourY2, P.x); |
361 | 0 | aZ4 = mr.Multiply(aZ4, sixteenY4); |
362 | 0 | M = mr.Square(P.x); |
363 | 0 | M = mr.Add(mr.Add(mr.Double(M), M), aZ4); |
364 | 0 | P.x = mr.Square(M); |
365 | 0 | mr.Reduce(P.x, S); |
366 | 0 | mr.Reduce(P.x, S); |
367 | 0 | mr.Reduce(S, P.x); |
368 | 0 | P.y = mr.Multiply(M, S); |
369 | 0 | sixteenY4 = mr.Square(fourY2); |
370 | 0 | mr.Reduce(P.y, mr.Half(sixteenY4)); |
371 | 0 | } |
372 | | |
373 | | const ModularArithmetic &mr; |
374 | | ProjectivePoint P; |
375 | | Integer sixteenY4, aZ4, twoY, fourY2, S, M; |
376 | | }; |
377 | | |
378 | | struct ZIterator |
379 | | { |
380 | 0 | ZIterator() {} |
381 | 0 | ZIterator(std::vector<ProjectivePoint>::iterator it) : it(it) {} |
382 | 0 | Integer& operator*() {return it->z;} |
383 | 0 | int operator-(ZIterator it2) {return int(it-it2.it);} |
384 | 0 | ZIterator operator+(int i) {return ZIterator(it+i);} |
385 | 0 | ZIterator& operator+=(int i) {it+=i; return *this;} |
386 | | std::vector<ProjectivePoint>::iterator it; |
387 | | }; |
388 | | |
389 | | ECP::Point ECP::ScalarMultiply(const Point &P, const Integer &k) const |
390 | 0 | { |
391 | 0 | Element result; |
392 | 0 | if (k.BitCount() <= 5) |
393 | 0 | AbstractGroup<ECPPoint>::SimultaneousMultiply(&result, P, &k, 1); |
394 | 0 | else |
395 | 0 | ECP::SimultaneousMultiply(&result, P, &k, 1); |
396 | 0 | return result; |
397 | 0 | } |
398 | | |
399 | | void ECP::SimultaneousMultiply(ECP::Point *results, const ECP::Point &P, const Integer *expBegin, unsigned int expCount) const |
400 | 0 | { |
401 | 0 | if (!GetField().IsMontgomeryRepresentation()) |
402 | 0 | { |
403 | 0 | ECP ecpmr(*this, true); |
404 | 0 | const ModularArithmetic &mr = ecpmr.GetField(); |
405 | 0 | ecpmr.SimultaneousMultiply(results, ToMontgomery(mr, P), expBegin, expCount); |
406 | 0 | for (unsigned int i=0; i<expCount; i++) |
407 | 0 | results[i] = FromMontgomery(mr, results[i]); |
408 | 0 | return; |
409 | 0 | } |
410 | | |
411 | 0 | ProjectiveDoubling rd(GetField(), m_a, m_b, P); |
412 | 0 | std::vector<ProjectivePoint> bases; |
413 | 0 | std::vector<WindowSlider> exponents; |
414 | 0 | exponents.reserve(expCount); |
415 | 0 | std::vector<std::vector<word32> > baseIndices(expCount); |
416 | 0 | std::vector<std::vector<bool> > negateBase(expCount); |
417 | 0 | std::vector<std::vector<word32> > exponentWindows(expCount); |
418 | 0 | unsigned int i; |
419 | |
|
420 | 0 | for (i=0; i<expCount; i++) |
421 | 0 | { |
422 | 0 | CRYPTOPP_ASSERT(expBegin->NotNegative()); |
423 | 0 | exponents.push_back(WindowSlider(*expBegin++, InversionIsFast(), 5)); |
424 | 0 | exponents[i].FindNextWindow(); |
425 | 0 | } |
426 | |
|
427 | 0 | unsigned int expBitPosition = 0; |
428 | 0 | bool notDone = true; |
429 | |
|
430 | 0 | while (notDone) |
431 | 0 | { |
432 | 0 | notDone = false; |
433 | 0 | bool baseAdded = false; |
434 | 0 | for (i=0; i<expCount; i++) |
435 | 0 | { |
436 | 0 | if (!exponents[i].finished && expBitPosition == exponents[i].windowBegin) |
437 | 0 | { |
438 | 0 | if (!baseAdded) |
439 | 0 | { |
440 | 0 | bases.push_back(rd.P); |
441 | 0 | baseAdded =true; |
442 | 0 | } |
443 | |
|
444 | 0 | exponentWindows[i].push_back(exponents[i].expWindow); |
445 | 0 | baseIndices[i].push_back((word32)bases.size()-1); |
446 | 0 | negateBase[i].push_back(exponents[i].negateNext); |
447 | |
|
448 | 0 | exponents[i].FindNextWindow(); |
449 | 0 | } |
450 | 0 | notDone = notDone || !exponents[i].finished; |
451 | 0 | } |
452 | |
|
453 | 0 | if (notDone) |
454 | 0 | { |
455 | 0 | rd.Double(); |
456 | 0 | expBitPosition++; |
457 | 0 | } |
458 | 0 | } |
459 | | |
460 | | // convert from projective to affine coordinates |
461 | 0 | ParallelInvert(GetField(), ZIterator(bases.begin()), ZIterator(bases.end())); |
462 | 0 | for (i=0; i<bases.size(); i++) |
463 | 0 | { |
464 | 0 | if (bases[i].z.NotZero()) |
465 | 0 | { |
466 | 0 | bases[i].y = GetField().Multiply(bases[i].y, bases[i].z); |
467 | 0 | bases[i].z = GetField().Square(bases[i].z); |
468 | 0 | bases[i].x = GetField().Multiply(bases[i].x, bases[i].z); |
469 | 0 | bases[i].y = GetField().Multiply(bases[i].y, bases[i].z); |
470 | 0 | } |
471 | 0 | } |
472 | |
|
473 | 0 | std::vector<BaseAndExponent<Point, Integer> > finalCascade; |
474 | 0 | for (i=0; i<expCount; i++) |
475 | 0 | { |
476 | 0 | finalCascade.resize(baseIndices[i].size()); |
477 | 0 | for (unsigned int j=0; j<baseIndices[i].size(); j++) |
478 | 0 | { |
479 | 0 | ProjectivePoint &base = bases[baseIndices[i][j]]; |
480 | 0 | if (base.z.IsZero()) |
481 | 0 | finalCascade[j].base.identity = true; |
482 | 0 | else |
483 | 0 | { |
484 | 0 | finalCascade[j].base.identity = false; |
485 | 0 | finalCascade[j].base.x = base.x; |
486 | 0 | if (negateBase[i][j]) |
487 | 0 | finalCascade[j].base.y = GetField().Inverse(base.y); |
488 | 0 | else |
489 | 0 | finalCascade[j].base.y = base.y; |
490 | 0 | } |
491 | 0 | finalCascade[j].exponent = Integer(Integer::POSITIVE, 0, exponentWindows[i][j]); |
492 | 0 | } |
493 | 0 | results[i] = GeneralCascadeMultiplication(*this, finalCascade.begin(), finalCascade.end()); |
494 | 0 | } |
495 | 0 | } |
496 | | |
497 | | ECP::Point ECP::CascadeScalarMultiply(const Point &P, const Integer &k1, const Point &Q, const Integer &k2) const |
498 | 0 | { |
499 | 0 | if (!GetField().IsMontgomeryRepresentation()) |
500 | 0 | { |
501 | 0 | ECP ecpmr(*this, true); |
502 | 0 | const ModularArithmetic &mr = ecpmr.GetField(); |
503 | 0 | return FromMontgomery(mr, ecpmr.CascadeScalarMultiply(ToMontgomery(mr, P), k1, ToMontgomery(mr, Q), k2)); |
504 | 0 | } |
505 | 0 | else |
506 | 0 | return AbstractGroup<Point>::CascadeScalarMultiply(P, k1, Q, k2); |
507 | 0 | } |
508 | | |
509 | | NAMESPACE_END |
510 | | |
511 | | #endif |