Line | Count | Source (jump to first uncovered line) |
1 | | // gf2n.cpp - originally written and placed in the public domain by Wei Dai |
2 | | |
3 | | #include "pch.h" |
4 | | #include "config.h" |
5 | | |
6 | | #ifndef CRYPTOPP_IMPORTS |
7 | | |
8 | | #include "cryptlib.h" |
9 | | #include "algebra.h" |
10 | | #include "randpool.h" |
11 | | #include "filters.h" |
12 | | #include "smartptr.h" |
13 | | #include "words.h" |
14 | | #include "misc.h" |
15 | | #include "gf2n.h" |
16 | | #include "oids.h" |
17 | | #include "asn.h" |
18 | | #include "cpu.h" |
19 | | |
20 | | #include <iostream> |
21 | | |
22 | | ANONYMOUS_NAMESPACE_BEGIN |
23 | | |
24 | | using CryptoPP::PolynomialMod2; |
25 | | |
26 | | #if defined(HAVE_GCC_INIT_PRIORITY) |
27 | | const PolynomialMod2 g_zero __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 60))) = PolynomialMod2(); |
28 | | const PolynomialMod2 g_one __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 61))) = PolynomialMod2(1); |
29 | | #elif defined(HAVE_MSC_INIT_PRIORITY) |
30 | | #pragma warning(disable: 4075) |
31 | | #pragma init_seg(".CRT$XCU") |
32 | | const PolynomialMod2 g_zero; |
33 | | const PolynomialMod2 g_one(1); |
34 | | #pragma warning(default: 4075) |
35 | | #elif defined(HAVE_XLC_INIT_PRIORITY) |
36 | | #pragma priority(290) |
37 | | const PolynomialMod2 g_zero; |
38 | | const PolynomialMod2 g_one(1); |
39 | | #endif |
40 | | |
41 | | ANONYMOUS_NAMESPACE_END |
42 | | |
43 | | NAMESPACE_BEGIN(CryptoPP) |
44 | | |
45 | | #if (CRYPTOPP_CLMUL_AVAILABLE) |
46 | | extern CRYPTOPP_DLL void GF2NT_233_Multiply_Reduce_CLMUL(const word* pA, const word* pB, word* pC); |
47 | | extern CRYPTOPP_DLL void GF2NT_233_Square_Reduce_CLMUL(const word* pA, word* pC); |
48 | | #endif |
49 | | |
50 | | #if (CRYPTOPP_ARM_PMULL_AVAILABLE) |
51 | | extern void GF2NT_233_Multiply_Reduce_ARMv8(const word* pA, const word* pB, word* pC); |
52 | | extern void GF2NT_233_Square_Reduce_ARMv8(const word* pA, word* pC); |
53 | | #endif |
54 | | |
55 | | #if (CRYPTOPP_POWER8_VMULL_AVAILABLE) && 0 |
56 | | extern void GF2NT_233_Multiply_Reduce_POWER8(const word* pA, const word* pB, word* pC); |
57 | | extern void GF2NT_233_Square_Reduce_POWER8(const word* pA, word* pC); |
58 | | #endif |
59 | | |
60 | | PolynomialMod2::PolynomialMod2() |
61 | 30 | { |
62 | 30 | } |
63 | | |
64 | | PolynomialMod2::PolynomialMod2(word value, size_t bitLength) |
65 | | : reg(BitsToWords(bitLength)) |
66 | 10 | { |
67 | 10 | CRYPTOPP_ASSERT(value==0 || reg.size()>0); |
68 | | |
69 | 10 | if (reg.size() > 0) |
70 | 10 | { |
71 | 10 | reg[0] = value; |
72 | 10 | SetWords(reg+1, 0, reg.size()-1); |
73 | 10 | } |
74 | 10 | } |
75 | | |
76 | | PolynomialMod2::PolynomialMod2(const PolynomialMod2& t) |
77 | | : reg(t.reg.size()) |
78 | 0 | { |
79 | 0 | CopyWords(reg, t.reg, reg.size()); |
80 | 0 | } |
81 | | |
82 | | void PolynomialMod2::Randomize(RandomNumberGenerator &rng, size_t nbits) |
83 | 0 | { |
84 | 0 | const size_t nbytes = nbits/8 + 1; |
85 | 0 | SecByteBlock buf(nbytes); |
86 | 0 | rng.GenerateBlock(buf, nbytes); |
87 | 0 | buf[0] = (byte)Crop(buf[0], nbits % 8); |
88 | 0 | Decode(buf, nbytes); |
89 | 0 | } |
90 | | |
91 | | PolynomialMod2 PolynomialMod2::AllOnes(size_t bitLength) |
92 | 0 | { |
93 | 0 | PolynomialMod2 result((word)0, bitLength); |
94 | 0 | SetWords(result.reg, ~(word(0)), result.reg.size()); |
95 | 0 | if (bitLength%WORD_BITS) |
96 | 0 | result.reg[result.reg.size()-1] = (word)Crop(result.reg[result.reg.size()-1], bitLength%WORD_BITS); |
97 | 0 | return result; |
98 | 0 | } |
99 | | |
100 | | void PolynomialMod2::SetBit(size_t n, int value) |
101 | 0 | { |
102 | 0 | if (value) |
103 | 0 | { |
104 | 0 | reg.CleanGrow(n/WORD_BITS + 1); |
105 | 0 | reg[n/WORD_BITS] |= (word(1) << (n%WORD_BITS)); |
106 | 0 | } |
107 | 0 | else |
108 | 0 | { |
109 | 0 | if (n/WORD_BITS < reg.size()) |
110 | 0 | reg[n/WORD_BITS] &= ~(word(1) << (n%WORD_BITS)); |
111 | 0 | } |
112 | 0 | } |
113 | | |
114 | | byte PolynomialMod2::GetByte(size_t n) const |
115 | 0 | { |
116 | 0 | if (n/WORD_SIZE >= reg.size()) |
117 | 0 | return 0; |
118 | 0 | else |
119 | 0 | return byte(reg[n/WORD_SIZE] >> ((n%WORD_SIZE)*8)); |
120 | 0 | } |
121 | | |
122 | | void PolynomialMod2::SetByte(size_t n, byte value) |
123 | 0 | { |
124 | 0 | reg.CleanGrow(BytesToWords(n+1)); |
125 | 0 | reg[n/WORD_SIZE] &= ~(word(0xff) << 8*(n%WORD_SIZE)); |
126 | 0 | reg[n/WORD_SIZE] |= (word(value) << 8*(n%WORD_SIZE)); |
127 | 0 | } |
128 | | |
129 | | PolynomialMod2 PolynomialMod2::Monomial(size_t i) |
130 | 0 | { |
131 | 0 | PolynomialMod2 r((word)0, i+1); |
132 | 0 | r.SetBit(i); |
133 | 0 | return r; |
134 | 0 | } |
135 | | |
136 | | PolynomialMod2 PolynomialMod2::Trinomial(size_t t0, size_t t1, size_t t2) |
137 | 0 | { |
138 | | // Asserts and checks due to Bing Shi |
139 | 0 | CRYPTOPP_ASSERT(t0 > t1); |
140 | 0 | CRYPTOPP_ASSERT(t1 > t2); |
141 | | |
142 | | // The test is relaxed because of ECIES<EC2N>. The high order exponent is t0, but the other exponents are not in descending order. |
143 | 0 | if (t1 > t0 || t2 > t0) |
144 | 0 | throw InvalidArgument("PolynomialMod2: exponents must be in descending order"); |
145 | | |
146 | 0 | PolynomialMod2 r((word)0, t0+1); |
147 | 0 | r.SetBit(t0); |
148 | 0 | r.SetBit(t1); |
149 | 0 | r.SetBit(t2); |
150 | 0 | return r; |
151 | 0 | } |
152 | | |
153 | | PolynomialMod2 PolynomialMod2::Pentanomial(size_t t0, size_t t1, size_t t2, size_t t3, size_t t4) |
154 | 0 | { |
155 | | // Asserts and checks due to Bing Shi |
156 | 0 | CRYPTOPP_ASSERT(t0 > t1); |
157 | 0 | CRYPTOPP_ASSERT(t1 > t2); |
158 | 0 | CRYPTOPP_ASSERT(t2 > t3); |
159 | 0 | CRYPTOPP_ASSERT(t3 > t4); |
160 | | |
161 | | // The test is relaxed because of ECIES<EC2N>. The high order exponent is t0, but the other exponents are not in descending order. |
162 | 0 | if (t1 > t0 || t2 > t0 || t3 > t0 || t4 > t0) |
163 | 0 | throw InvalidArgument("PolynomialMod2: exponents must be in descending order"); |
164 | | |
165 | 0 | PolynomialMod2 r((word)0, t0+1); |
166 | 0 | r.SetBit(t0); |
167 | 0 | r.SetBit(t1); |
168 | 0 | r.SetBit(t2); |
169 | 0 | r.SetBit(t3); |
170 | 0 | r.SetBit(t4); |
171 | 0 | return r; |
172 | 0 | } |
173 | | |
174 | | template <word i> |
175 | | struct NewPolynomialMod2 |
176 | | { |
177 | | PolynomialMod2 * operator()() const |
178 | | { |
179 | | return new PolynomialMod2(i); |
180 | | } |
181 | | }; |
182 | | |
183 | | const PolynomialMod2 &PolynomialMod2::Zero() |
184 | 0 | { |
185 | 0 | #if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY) || defined(HAVE_XLC_INIT_PRIORITY) |
186 | 0 | return g_zero; |
187 | | #elif defined(CRYPTOPP_CXX11_STATIC_INIT) |
188 | | static const PolynomialMod2 g_zero; |
189 | | return g_zero; |
190 | | #else |
191 | | return Singleton<PolynomialMod2>().Ref(); |
192 | | #endif |
193 | 0 | } |
194 | | |
195 | | const PolynomialMod2 &PolynomialMod2::One() |
196 | 0 | { |
197 | 0 | #if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY) || defined(HAVE_XLC_INIT_PRIORITY) |
198 | 0 | return g_one; |
199 | | #elif defined(CRYPTOPP_CXX11_STATIC_INIT) |
200 | | static const PolynomialMod2 g_one(1); |
201 | | return g_one; |
202 | | #else |
203 | | return Singleton<PolynomialMod2, NewPolynomialMod2<1> >().Ref(); |
204 | | #endif |
205 | 0 | } |
206 | | |
207 | | void PolynomialMod2::Decode(const byte *input, size_t inputLen) |
208 | 0 | { |
209 | 0 | StringStore store(input, inputLen); |
210 | 0 | Decode(store, inputLen); |
211 | 0 | } |
212 | | |
213 | | void PolynomialMod2::Encode(byte *output, size_t outputLen) const |
214 | 0 | { |
215 | 0 | ArraySink sink(output, outputLen); |
216 | 0 | Encode(sink, outputLen); |
217 | 0 | } |
218 | | |
219 | | void PolynomialMod2::Decode(BufferedTransformation &bt, size_t inputLen) |
220 | 0 | { |
221 | 0 | CRYPTOPP_ASSERT(bt.MaxRetrievable() >= inputLen); |
222 | 0 | if (bt.MaxRetrievable() < inputLen) |
223 | 0 | throw InvalidArgument("PolynomialMod2: input length is too small"); |
224 | | |
225 | 0 | reg.CleanNew(BytesToWords(inputLen)); |
226 | |
|
227 | 0 | for (size_t i=inputLen; i > 0; i--) |
228 | 0 | { |
229 | 0 | byte b; |
230 | 0 | (void)bt.Get(b); |
231 | 0 | reg[(i-1)/WORD_SIZE] |= word(b) << ((i-1)%WORD_SIZE)*8; |
232 | 0 | } |
233 | 0 | } |
234 | | |
235 | | void PolynomialMod2::Encode(BufferedTransformation &bt, size_t outputLen) const |
236 | 0 | { |
237 | 0 | for (size_t i=outputLen; i > 0; i--) |
238 | 0 | bt.Put(GetByte(i-1)); |
239 | 0 | } |
240 | | |
241 | | void PolynomialMod2::DEREncodeAsOctetString(BufferedTransformation &bt, size_t length) const |
242 | 0 | { |
243 | 0 | DERGeneralEncoder enc(bt, OCTET_STRING); |
244 | 0 | Encode(enc, length); |
245 | 0 | enc.MessageEnd(); |
246 | 0 | } |
247 | | |
248 | | void PolynomialMod2::BERDecodeAsOctetString(BufferedTransformation &bt, size_t length) |
249 | 0 | { |
250 | 0 | BERGeneralDecoder dec(bt, OCTET_STRING); |
251 | 0 | if (!dec.IsDefiniteLength() || dec.RemainingLength() != length) |
252 | 0 | BERDecodeError(); |
253 | 0 | Decode(dec, length); |
254 | 0 | dec.MessageEnd(); |
255 | 0 | } |
256 | | |
257 | | unsigned int PolynomialMod2::WordCount() const |
258 | 0 | { |
259 | 0 | return (unsigned int)CountWords(reg, reg.size()); |
260 | 0 | } |
261 | | |
262 | | unsigned int PolynomialMod2::ByteCount() const |
263 | 0 | { |
264 | 0 | unsigned wordCount = WordCount(); |
265 | 0 | if (wordCount) |
266 | 0 | return (wordCount-1)*WORD_SIZE + BytePrecision(reg[wordCount-1]); |
267 | 0 | else |
268 | 0 | return 0; |
269 | 0 | } |
270 | | |
271 | | unsigned int PolynomialMod2::BitCount() const |
272 | 0 | { |
273 | 0 | unsigned wordCount = WordCount(); |
274 | 0 | if (wordCount) |
275 | 0 | return (wordCount-1)*WORD_BITS + BitPrecision(reg[wordCount-1]); |
276 | 0 | else |
277 | 0 | return 0; |
278 | 0 | } |
279 | | |
280 | | unsigned int PolynomialMod2::Parity() const |
281 | 0 | { |
282 | 0 | unsigned i; |
283 | 0 | word temp=0; |
284 | 0 | for (i=0; i<reg.size(); i++) |
285 | 0 | temp ^= reg[i]; |
286 | 0 | return CryptoPP::Parity(temp); |
287 | 0 | } |
288 | | |
289 | | PolynomialMod2& PolynomialMod2::operator=(const PolynomialMod2& t) |
290 | 0 | { |
291 | 0 | reg.Assign(t.reg); |
292 | 0 | return *this; |
293 | 0 | } |
294 | | |
295 | | PolynomialMod2& PolynomialMod2::operator^=(const PolynomialMod2& t) |
296 | 0 | { |
297 | 0 | reg.CleanGrow(t.reg.size()); |
298 | 0 | XorWords(reg, t.reg, t.reg.size()); |
299 | 0 | return *this; |
300 | 0 | } |
301 | | |
302 | | PolynomialMod2 PolynomialMod2::Xor(const PolynomialMod2 &b) const |
303 | 0 | { |
304 | 0 | if (b.reg.size() >= reg.size()) |
305 | 0 | { |
306 | 0 | PolynomialMod2 result((word)0, b.reg.size()*WORD_BITS); |
307 | 0 | XorWords(result.reg, reg, b.reg, reg.size()); |
308 | 0 | CopyWords(result.reg+reg.size(), b.reg+reg.size(), b.reg.size()-reg.size()); |
309 | 0 | return result; |
310 | 0 | } |
311 | 0 | else |
312 | 0 | { |
313 | 0 | PolynomialMod2 result((word)0, reg.size()*WORD_BITS); |
314 | 0 | XorWords(result.reg, reg, b.reg, b.reg.size()); |
315 | 0 | CopyWords(result.reg+b.reg.size(), reg+b.reg.size(), reg.size()-b.reg.size()); |
316 | 0 | return result; |
317 | 0 | } |
318 | 0 | } |
319 | | |
320 | | PolynomialMod2 PolynomialMod2::And(const PolynomialMod2 &b) const |
321 | 0 | { |
322 | 0 | PolynomialMod2 result((word)0, WORD_BITS*STDMIN(reg.size(), b.reg.size())); |
323 | 0 | AndWords(result.reg, reg, b.reg, result.reg.size()); |
324 | 0 | return result; |
325 | 0 | } |
326 | | |
327 | | PolynomialMod2 PolynomialMod2::Times(const PolynomialMod2 &b) const |
328 | 0 | { |
329 | 0 | PolynomialMod2 result((word)0, BitCount() + b.BitCount()); |
330 | |
|
331 | 0 | for (int i=b.Degree(); i>=0; i--) |
332 | 0 | { |
333 | 0 | result <<= 1; |
334 | 0 | if (b[i]) |
335 | 0 | XorWords(result.reg, reg, reg.size()); |
336 | 0 | } |
337 | 0 | return result; |
338 | 0 | } |
339 | | |
340 | | PolynomialMod2 PolynomialMod2::Squared() const |
341 | 0 | { |
342 | 0 | static const word map[16] = {0, 1, 4, 5, 16, 17, 20, 21, 64, 65, 68, 69, 80, 81, 84, 85}; |
343 | |
|
344 | 0 | PolynomialMod2 result((word)0, 2*reg.size()*WORD_BITS); |
345 | |
|
346 | 0 | for (unsigned i=0; i<reg.size(); i++) |
347 | 0 | { |
348 | 0 | unsigned j; |
349 | |
|
350 | 0 | for (j=0; j<WORD_BITS; j+=8) |
351 | 0 | result.reg[2*i] |= map[(reg[i] >> (j/2)) % 16] << j; |
352 | |
|
353 | 0 | for (j=0; j<WORD_BITS; j+=8) |
354 | 0 | result.reg[2*i+1] |= map[(reg[i] >> (j/2 + WORD_BITS/2)) % 16] << j; |
355 | 0 | } |
356 | |
|
357 | 0 | return result; |
358 | 0 | } |
359 | | |
360 | | void PolynomialMod2::Divide(PolynomialMod2 &remainder, PolynomialMod2 "ient, |
361 | | const PolynomialMod2 ÷nd, const PolynomialMod2 &divisor) |
362 | 0 | { |
363 | 0 | if (!divisor) |
364 | 0 | throw PolynomialMod2::DivideByZero(); |
365 | | |
366 | 0 | int degree = divisor.Degree(); |
367 | 0 | remainder.reg.CleanNew(BitsToWords(degree+1)); |
368 | 0 | if (dividend.BitCount() >= divisor.BitCount()) |
369 | 0 | quotient.reg.CleanNew(BitsToWords(dividend.BitCount() - divisor.BitCount() + 1)); |
370 | 0 | else |
371 | 0 | quotient.reg.CleanNew(0); |
372 | |
|
373 | 0 | for (int i=dividend.Degree(); i>=0; i--) |
374 | 0 | { |
375 | 0 | remainder <<= 1; |
376 | 0 | remainder.reg[0] |= dividend[i]; |
377 | 0 | if (remainder[degree]) |
378 | 0 | { |
379 | 0 | remainder -= divisor; |
380 | 0 | quotient.SetBit(i); |
381 | 0 | } |
382 | 0 | } |
383 | 0 | } |
384 | | |
385 | | PolynomialMod2 PolynomialMod2::DividedBy(const PolynomialMod2 &b) const |
386 | 0 | { |
387 | 0 | PolynomialMod2 remainder, quotient; |
388 | 0 | PolynomialMod2::Divide(remainder, quotient, *this, b); |
389 | 0 | return quotient; |
390 | 0 | } |
391 | | |
392 | | PolynomialMod2 PolynomialMod2::Modulo(const PolynomialMod2 &b) const |
393 | 0 | { |
394 | 0 | PolynomialMod2 remainder, quotient; |
395 | 0 | PolynomialMod2::Divide(remainder, quotient, *this, b); |
396 | 0 | return remainder; |
397 | 0 | } |
398 | | |
399 | | PolynomialMod2& PolynomialMod2::operator<<=(unsigned int n) |
400 | 0 | { |
401 | | #if defined(CRYPTOPP_DEBUG) |
402 | | int x=0; CRYPTOPP_UNUSED(x); |
403 | | CRYPTOPP_ASSERT(SafeConvert(n,x)); |
404 | | #endif |
405 | |
|
406 | 0 | if (!reg.size()) |
407 | 0 | return *this; |
408 | | |
409 | 0 | int i; |
410 | 0 | word u; |
411 | 0 | word carry=0; |
412 | 0 | word *r=reg; |
413 | |
|
414 | 0 | if (n==1) // special case code for most frequent case |
415 | 0 | { |
416 | 0 | i = (int)reg.size(); |
417 | 0 | while (i--) |
418 | 0 | { |
419 | 0 | u = *r; |
420 | 0 | *r = (u << 1) | carry; |
421 | 0 | carry = u >> (WORD_BITS-1); |
422 | 0 | r++; |
423 | 0 | } |
424 | |
|
425 | 0 | if (carry) |
426 | 0 | { |
427 | 0 | reg.Grow(reg.size()+1); |
428 | 0 | reg[reg.size()-1] = carry; |
429 | 0 | } |
430 | |
|
431 | 0 | return *this; |
432 | 0 | } |
433 | | |
434 | 0 | const int shiftWords = n / WORD_BITS; |
435 | 0 | const int shiftBits = n % WORD_BITS; |
436 | |
|
437 | 0 | if (shiftBits) |
438 | 0 | { |
439 | 0 | i = (int)reg.size(); |
440 | 0 | while (i--) |
441 | 0 | { |
442 | 0 | u = *r; |
443 | 0 | *r = (u << shiftBits) | carry; |
444 | 0 | carry = u >> (WORD_BITS-shiftBits); |
445 | 0 | r++; |
446 | 0 | } |
447 | 0 | } |
448 | |
|
449 | 0 | if (carry) |
450 | 0 | { |
451 | | // Thanks to Apatryda, http://github.com/weidai11/cryptopp/issues/64 |
452 | 0 | const size_t carryIndex = reg.size(); |
453 | 0 | reg.Grow(reg.size()+shiftWords+!!shiftBits); |
454 | 0 | reg[carryIndex] = carry; |
455 | 0 | } |
456 | 0 | else |
457 | 0 | reg.Grow(reg.size()+shiftWords); |
458 | |
|
459 | 0 | if (shiftWords) |
460 | 0 | { |
461 | 0 | for (i = (int)reg.size()-1; i>=shiftWords; i--) |
462 | 0 | reg[i] = reg[i-shiftWords]; |
463 | 0 | for (; i>=0; i--) |
464 | 0 | reg[i] = 0; |
465 | 0 | } |
466 | |
|
467 | 0 | return *this; |
468 | 0 | } |
469 | | |
470 | | PolynomialMod2& PolynomialMod2::operator>>=(unsigned int n) |
471 | 0 | { |
472 | 0 | if (!reg.size()) |
473 | 0 | return *this; |
474 | | |
475 | 0 | int shiftWords = n / WORD_BITS; |
476 | 0 | int shiftBits = n % WORD_BITS; |
477 | |
|
478 | 0 | size_t i; |
479 | 0 | word u; |
480 | 0 | word carry=0; |
481 | 0 | word *r=reg+reg.size()-1; |
482 | |
|
483 | 0 | if (shiftBits) |
484 | 0 | { |
485 | 0 | i = reg.size(); |
486 | 0 | while (i--) |
487 | 0 | { |
488 | 0 | u = *r; |
489 | 0 | *r = (u >> shiftBits) | carry; |
490 | 0 | carry = u << (WORD_BITS-shiftBits); |
491 | 0 | r--; |
492 | 0 | } |
493 | 0 | } |
494 | |
|
495 | 0 | if (shiftWords) |
496 | 0 | { |
497 | 0 | for (i=0; i<reg.size()-shiftWords; i++) |
498 | 0 | reg[i] = reg[i+shiftWords]; |
499 | 0 | for (; i<reg.size(); i++) |
500 | 0 | reg[i] = 0; |
501 | 0 | } |
502 | |
|
503 | 0 | return *this; |
504 | 0 | } |
505 | | |
506 | | PolynomialMod2 PolynomialMod2::operator<<(unsigned int n) const |
507 | 0 | { |
508 | 0 | PolynomialMod2 result(*this); |
509 | 0 | return result<<=n; |
510 | 0 | } |
511 | | |
512 | | PolynomialMod2 PolynomialMod2::operator>>(unsigned int n) const |
513 | 0 | { |
514 | 0 | PolynomialMod2 result(*this); |
515 | 0 | return result>>=n; |
516 | 0 | } |
517 | | |
518 | | bool PolynomialMod2::operator!() const |
519 | 0 | { |
520 | 0 | for (unsigned i=0; i<reg.size(); i++) |
521 | 0 | if (reg[i]) return false; |
522 | 0 | return true; |
523 | 0 | } |
524 | | |
525 | | bool PolynomialMod2::Equals(const PolynomialMod2 &rhs) const |
526 | 0 | { |
527 | 0 | size_t i, smallerSize = STDMIN(reg.size(), rhs.reg.size()); |
528 | |
|
529 | 0 | for (i=0; i<smallerSize; i++) |
530 | 0 | if (reg[i] != rhs.reg[i]) return false; |
531 | | |
532 | 0 | for (i=smallerSize; i<reg.size(); i++) |
533 | 0 | if (reg[i] != 0) return false; |
534 | | |
535 | 0 | for (i=smallerSize; i<rhs.reg.size(); i++) |
536 | 0 | if (rhs.reg[i] != 0) return false; |
537 | | |
538 | 0 | return true; |
539 | 0 | } |
540 | | |
541 | | std::ostream& operator<<(std::ostream& out, const PolynomialMod2 &a) |
542 | 0 | { |
543 | | // Get relevant conversion specifications from ostream. |
544 | 0 | long f = out.flags() & std::ios::basefield; // Get base digits. |
545 | 0 | int bits, block; |
546 | 0 | char suffix; |
547 | 0 | switch(f) |
548 | 0 | { |
549 | 0 | case std::ios::oct : |
550 | 0 | bits = 3; |
551 | 0 | block = 4; |
552 | 0 | suffix = 'o'; |
553 | 0 | break; |
554 | 0 | case std::ios::hex : |
555 | 0 | bits = 4; |
556 | 0 | block = 2; |
557 | 0 | suffix = 'h'; |
558 | 0 | break; |
559 | 0 | default : |
560 | 0 | bits = 1; |
561 | 0 | block = 8; |
562 | 0 | suffix = 'b'; |
563 | 0 | } |
564 | | |
565 | 0 | if (!a) |
566 | 0 | return out << '0' << suffix; |
567 | | |
568 | 0 | SecBlock<char> s(a.BitCount()/bits+1); |
569 | 0 | unsigned i; |
570 | |
|
571 | 0 | static const char upper[]="0123456789ABCDEF"; |
572 | 0 | static const char lower[]="0123456789abcdef"; |
573 | 0 | const char* const vec = (out.flags() & std::ios::uppercase) ? upper : lower; |
574 | |
|
575 | 0 | for (i=0; i*bits < a.BitCount(); i++) |
576 | 0 | { |
577 | 0 | int digit=0; |
578 | 0 | for (int j=0; j<bits; j++) |
579 | 0 | digit |= a[i*bits+j] << j; |
580 | 0 | s[i]=vec[digit]; |
581 | 0 | } |
582 | |
|
583 | 0 | while (i--) |
584 | 0 | { |
585 | 0 | out << s[i]; |
586 | 0 | if (i && (i%block)==0) |
587 | 0 | out << ','; |
588 | 0 | } |
589 | |
|
590 | 0 | return out << suffix; |
591 | 0 | } |
592 | | |
593 | | PolynomialMod2 PolynomialMod2::Gcd(const PolynomialMod2 &a, const PolynomialMod2 &b) |
594 | 0 | { |
595 | 0 | return EuclideanDomainOf<PolynomialMod2>().Gcd(a, b); |
596 | 0 | } |
597 | | |
598 | | PolynomialMod2 PolynomialMod2::InverseMod(const PolynomialMod2 &modulus) const |
599 | 0 | { |
600 | 0 | typedef EuclideanDomainOf<PolynomialMod2> Domain; |
601 | 0 | return QuotientRing<Domain>(Domain(), modulus).MultiplicativeInverse(*this); |
602 | 0 | } |
603 | | |
604 | | bool PolynomialMod2::IsIrreducible() const |
605 | 0 | { |
606 | 0 | signed int d = Degree(); |
607 | 0 | if (d <= 0) |
608 | 0 | return false; |
609 | | |
610 | 0 | PolynomialMod2 t(2), u(t); |
611 | 0 | for (int i=1; i<=d/2; i++) |
612 | 0 | { |
613 | 0 | u = u.Squared()%(*this); |
614 | 0 | if (!Gcd(u+t, *this).IsUnit()) |
615 | 0 | return false; |
616 | 0 | } |
617 | 0 | return true; |
618 | 0 | } |
619 | | |
620 | | // ******************************************************** |
621 | | |
622 | | GF2NP::GF2NP(const PolynomialMod2 &modulus) |
623 | | : QuotientRing<EuclideanDomainOf<PolynomialMod2> >(EuclideanDomainOf<PolynomialMod2>(), modulus), m(modulus.Degree()) |
624 | 0 | { |
625 | 0 | } |
626 | | |
627 | | GF2NP::Element GF2NP::SquareRoot(const Element &a) const |
628 | 0 | { |
629 | 0 | Element r = a; |
630 | 0 | for (unsigned int i=1; i<m; i++) |
631 | 0 | r = Square(r); |
632 | 0 | return r; |
633 | 0 | } |
634 | | |
635 | | GF2NP::Element GF2NP::HalfTrace(const Element &a) const |
636 | 0 | { |
637 | 0 | CRYPTOPP_ASSERT(m%2 == 1); |
638 | 0 | Element h = a; |
639 | 0 | for (unsigned int i=1; i<=(m-1)/2; i++) |
640 | 0 | h = Add(Square(Square(h)), a); |
641 | 0 | return h; |
642 | 0 | } |
643 | | |
644 | | GF2NP::Element GF2NP::SolveQuadraticEquation(const Element &a) const |
645 | 0 | { |
646 | 0 | if (m%2 == 0) |
647 | 0 | { |
648 | 0 | Element z, w; |
649 | 0 | RandomPool rng; |
650 | 0 | do |
651 | 0 | { |
652 | 0 | Element p((RandomNumberGenerator &)rng, m); |
653 | 0 | z = PolynomialMod2::Zero(); |
654 | 0 | w = p; |
655 | 0 | for (unsigned int i=1; i<=m-1; i++) |
656 | 0 | { |
657 | 0 | w = Square(w); |
658 | 0 | z = Square(z); |
659 | 0 | Accumulate(z, Multiply(w, a)); |
660 | 0 | Accumulate(w, p); |
661 | 0 | } |
662 | 0 | } while (w.IsZero()); |
663 | 0 | return z; |
664 | 0 | } |
665 | 0 | else |
666 | 0 | return HalfTrace(a); |
667 | 0 | } |
668 | | |
669 | | // ******************************************************** |
670 | | |
671 | | GF2NT::GF2NT(unsigned int c0, unsigned int c1, unsigned int c2) |
672 | | : GF2NP(PolynomialMod2::Trinomial(c0, c1, c2)) |
673 | | , t0(c0), t1(c1) |
674 | | , result((word)0, m) |
675 | 0 | { |
676 | | // Asserts and checks due to Bing Shi |
677 | 0 | CRYPTOPP_ASSERT(c0 > c1 && c1 > c2 && c2==0); |
678 | | |
679 | | // The test is relaxed because of ECIES<EC2N>. The high order exponent is t0, but the other exponents are not in descending order. |
680 | 0 | if (c1 > c0 || c2 > c0) |
681 | 0 | throw InvalidArgument("GF2NT: exponents must be in descending order"); |
682 | 0 | } |
683 | | |
684 | | const GF2NT::Element& GF2NT::MultiplicativeInverse(const Element &a) const |
685 | 0 | { |
686 | 0 | if (t0-t1 < WORD_BITS) |
687 | 0 | return GF2NP::MultiplicativeInverse(a); |
688 | | |
689 | 0 | SecWordBlock T(m_modulus.reg.size() * 4); |
690 | 0 | word *b = T; |
691 | 0 | word *c = T+m_modulus.reg.size(); |
692 | 0 | word *f = T+2*m_modulus.reg.size(); |
693 | 0 | word *g = T+3*m_modulus.reg.size(); |
694 | 0 | size_t bcLen=1, fgLen=m_modulus.reg.size(); |
695 | 0 | unsigned int k=0; |
696 | |
|
697 | 0 | SetWords(T, 0, 3*m_modulus.reg.size()); |
698 | 0 | b[0]=1; |
699 | 0 | CRYPTOPP_ASSERT(a.reg.size() <= m_modulus.reg.size()); |
700 | 0 | CopyWords(f, a.reg, a.reg.size()); |
701 | 0 | CopyWords(g, m_modulus.reg, m_modulus.reg.size()); |
702 | |
|
703 | 0 | while (1) |
704 | 0 | { |
705 | 0 | word t=f[0]; |
706 | 0 | while (!t) |
707 | 0 | { |
708 | 0 | ShiftWordsRightByWords(f, fgLen, 1); |
709 | 0 | if (c[bcLen-1]) |
710 | 0 | bcLen++; |
711 | 0 | CRYPTOPP_ASSERT(bcLen <= m_modulus.reg.size()); |
712 | 0 | ShiftWordsLeftByWords(c, bcLen, 1); |
713 | 0 | k+=WORD_BITS; |
714 | 0 | t=f[0]; |
715 | 0 | } |
716 | |
|
717 | 0 | unsigned int i=0; |
718 | 0 | while (t%2 == 0) |
719 | 0 | { |
720 | 0 | t>>=1; |
721 | 0 | i++; |
722 | 0 | } |
723 | 0 | k+=i; |
724 | |
|
725 | 0 | if (t==1 && CountWords(f, fgLen)==1) |
726 | 0 | break; |
727 | | |
728 | 0 | if (i==1) |
729 | 0 | { |
730 | 0 | ShiftWordsRightByBits(f, fgLen, 1); |
731 | 0 | t=ShiftWordsLeftByBits(c, bcLen, 1); |
732 | 0 | } |
733 | 0 | else |
734 | 0 | { |
735 | 0 | ShiftWordsRightByBits(f, fgLen, i); |
736 | 0 | t=ShiftWordsLeftByBits(c, bcLen, i); |
737 | 0 | } |
738 | 0 | if (t) |
739 | 0 | { |
740 | 0 | c[bcLen] = t; |
741 | 0 | bcLen++; |
742 | 0 | CRYPTOPP_ASSERT(bcLen <= m_modulus.reg.size()); |
743 | 0 | } |
744 | |
|
745 | 0 | if (f[fgLen-1]==0 && g[fgLen-1]==0) |
746 | 0 | fgLen--; |
747 | |
|
748 | 0 | if (f[fgLen-1] < g[fgLen-1]) |
749 | 0 | { |
750 | 0 | std::swap(f, g); |
751 | 0 | std::swap(b, c); |
752 | 0 | } |
753 | |
|
754 | 0 | XorWords(f, g, fgLen); |
755 | 0 | XorWords(b, c, bcLen); |
756 | 0 | } |
757 | |
|
758 | 0 | while (k >= WORD_BITS) |
759 | 0 | { |
760 | 0 | word temp = b[0]; |
761 | | // right shift b |
762 | 0 | for (unsigned i=0; i+1<BitsToWords(m); i++) |
763 | 0 | b[i] = b[i+1]; |
764 | 0 | b[BitsToWords(m)-1] = 0; |
765 | |
|
766 | 0 | if (t1 < WORD_BITS) |
767 | 0 | for (unsigned int j=0; j<WORD_BITS-t1; j++) |
768 | 0 | { |
769 | | // Coverity finding on shift amount of 'word x << (t1+j)'. |
770 | | // temp ^= ((temp >> j) & 1) << (t1 + j); |
771 | 0 | const unsigned int shift = t1 + j; |
772 | 0 | CRYPTOPP_ASSERT(shift < WORD_BITS); |
773 | 0 | temp ^= (shift < WORD_BITS) ? (((temp >> j) & 1) << shift) : 0; |
774 | 0 | } |
775 | 0 | else |
776 | 0 | b[t1/WORD_BITS-1] ^= temp << t1%WORD_BITS; |
777 | |
|
778 | 0 | if (t1 % WORD_BITS) |
779 | 0 | b[t1/WORD_BITS] ^= temp >> (WORD_BITS - t1%WORD_BITS); |
780 | |
|
781 | 0 | if (t0%WORD_BITS) |
782 | 0 | { |
783 | 0 | b[t0/WORD_BITS-1] ^= temp << t0%WORD_BITS; |
784 | 0 | b[t0/WORD_BITS] ^= temp >> (WORD_BITS - t0%WORD_BITS); |
785 | 0 | } |
786 | 0 | else |
787 | 0 | b[t0/WORD_BITS-1] ^= temp; |
788 | |
|
789 | 0 | k -= WORD_BITS; |
790 | 0 | } |
791 | |
|
792 | 0 | if (k) |
793 | 0 | { |
794 | 0 | word temp = b[0] << (WORD_BITS - k); |
795 | 0 | ShiftWordsRightByBits(b, BitsToWords(m), k); |
796 | |
|
797 | 0 | if (t1 < WORD_BITS) |
798 | 0 | { |
799 | 0 | for (unsigned int j=0; j<WORD_BITS-t1; j++) |
800 | 0 | { |
801 | | // Coverity finding on shift amount of 'word x << (t1+j)'. |
802 | | // temp ^= ((temp >> j) & 1) << (t1 + j); |
803 | 0 | const unsigned int shift = t1 + j; |
804 | 0 | CRYPTOPP_ASSERT(shift < WORD_BITS); |
805 | 0 | temp ^= (shift < WORD_BITS) ? (((temp >> j) & 1) << shift) : 0; |
806 | 0 | } |
807 | 0 | } |
808 | 0 | else |
809 | 0 | { |
810 | 0 | b[t1/WORD_BITS-1] ^= temp << t1%WORD_BITS; |
811 | 0 | } |
812 | |
|
813 | 0 | if (t1 % WORD_BITS) |
814 | 0 | b[t1/WORD_BITS] ^= temp >> (WORD_BITS - t1%WORD_BITS); |
815 | |
|
816 | 0 | if (t0%WORD_BITS) |
817 | 0 | { |
818 | 0 | b[t0/WORD_BITS-1] ^= temp << t0%WORD_BITS; |
819 | 0 | b[t0/WORD_BITS] ^= temp >> (WORD_BITS - t0%WORD_BITS); |
820 | 0 | } |
821 | 0 | else |
822 | 0 | b[t0/WORD_BITS-1] ^= temp; |
823 | 0 | } |
824 | |
|
825 | 0 | CopyWords(result.reg.begin(), b, result.reg.size()); |
826 | 0 | return result; |
827 | 0 | } |
828 | | |
829 | | const GF2NT::Element& GF2NT::Multiply(const Element &a, const Element &b) const |
830 | 0 | { |
831 | 0 | size_t aSize = STDMIN(a.reg.size(), result.reg.size()); |
832 | 0 | Element r((word)0, m); |
833 | |
|
834 | 0 | for (int i=m-1; i>=0; i--) |
835 | 0 | { |
836 | 0 | if (r[m-1]) |
837 | 0 | { |
838 | 0 | ShiftWordsLeftByBits(r.reg.begin(), r.reg.size(), 1); |
839 | 0 | XorWords(r.reg.begin(), m_modulus.reg, r.reg.size()); |
840 | 0 | } |
841 | 0 | else |
842 | 0 | ShiftWordsLeftByBits(r.reg.begin(), r.reg.size(), 1); |
843 | |
|
844 | 0 | if (b[i]) |
845 | 0 | XorWords(r.reg.begin(), a.reg, aSize); |
846 | 0 | } |
847 | |
|
848 | 0 | if (m%WORD_BITS) |
849 | 0 | r.reg.begin()[r.reg.size()-1] = (word)Crop(r.reg[r.reg.size()-1], m%WORD_BITS); |
850 | |
|
851 | 0 | CopyWords(result.reg.begin(), r.reg.begin(), result.reg.size()); |
852 | 0 | return result; |
853 | 0 | } |
854 | | |
855 | | const GF2NT::Element& GF2NT::Reduced(const Element &a) const |
856 | 0 | { |
857 | 0 | if (t0-t1 < WORD_BITS) |
858 | 0 | return m_domain.Mod(a, m_modulus); |
859 | | |
860 | 0 | SecWordBlock b(a.reg); |
861 | |
|
862 | 0 | size_t i; |
863 | 0 | for (i=b.size()-1; i>=BitsToWords(t0); i--) |
864 | 0 | { |
865 | 0 | word temp = b[i]; |
866 | |
|
867 | 0 | if (t0%WORD_BITS) |
868 | 0 | { |
869 | 0 | b[i-t0/WORD_BITS] ^= temp >> t0%WORD_BITS; |
870 | 0 | b[i-t0/WORD_BITS-1] ^= temp << (WORD_BITS - t0%WORD_BITS); |
871 | 0 | } |
872 | 0 | else |
873 | 0 | b[i-t0/WORD_BITS] ^= temp; |
874 | |
|
875 | 0 | if ((t0-t1)%WORD_BITS) |
876 | 0 | { |
877 | 0 | b[i-(t0-t1)/WORD_BITS] ^= temp >> (t0-t1)%WORD_BITS; |
878 | 0 | b[i-(t0-t1)/WORD_BITS-1] ^= temp << (WORD_BITS - (t0-t1)%WORD_BITS); |
879 | 0 | } |
880 | 0 | else |
881 | 0 | b[i-(t0-t1)/WORD_BITS] ^= temp; |
882 | 0 | } |
883 | |
|
884 | 0 | if (i==BitsToWords(t0)-1 && t0%WORD_BITS) |
885 | 0 | { |
886 | 0 | word mask = ((word)1<<(t0%WORD_BITS))-1; |
887 | 0 | word temp = b[i] & ~mask; |
888 | 0 | b[i] &= mask; |
889 | |
|
890 | 0 | b[i-t0/WORD_BITS] ^= temp >> t0%WORD_BITS; |
891 | |
|
892 | 0 | if ((t0-t1)%WORD_BITS) |
893 | 0 | { |
894 | 0 | b[i-(t0-t1)/WORD_BITS] ^= temp >> (t0-t1)%WORD_BITS; |
895 | 0 | if ((t0-t1)%WORD_BITS > t0%WORD_BITS) |
896 | 0 | b[i-(t0-t1)/WORD_BITS-1] ^= temp << (WORD_BITS - (t0-t1)%WORD_BITS); |
897 | 0 | else |
898 | 0 | CRYPTOPP_ASSERT(temp << (WORD_BITS - (t0-t1)%WORD_BITS) == 0); |
899 | 0 | } |
900 | 0 | else |
901 | 0 | b[i-(t0-t1)/WORD_BITS] ^= temp; |
902 | 0 | } |
903 | |
|
904 | 0 | SetWords(result.reg.begin(), 0, result.reg.size()); |
905 | 0 | CopyWords(result.reg.begin(), b, STDMIN(b.size(), result.reg.size())); |
906 | 0 | return result; |
907 | 0 | } |
908 | | |
909 | | void GF2NP::DEREncodeElement(BufferedTransformation &out, const Element &a) const |
910 | 0 | { |
911 | 0 | a.DEREncodeAsOctetString(out, MaxElementByteLength()); |
912 | 0 | } |
913 | | |
914 | | void GF2NP::BERDecodeElement(BufferedTransformation &in, Element &a) const |
915 | 0 | { |
916 | 0 | a.BERDecodeAsOctetString(in, MaxElementByteLength()); |
917 | 0 | } |
918 | | |
919 | | void GF2NT::DEREncode(BufferedTransformation &bt) const |
920 | 0 | { |
921 | 0 | DERSequenceEncoder seq(bt); |
922 | 0 | ASN1::characteristic_two_field().DEREncode(seq); |
923 | 0 | DERSequenceEncoder parameters(seq); |
924 | 0 | DEREncodeUnsigned(parameters, m); |
925 | 0 | ASN1::tpBasis().DEREncode(parameters); |
926 | 0 | DEREncodeUnsigned(parameters, t1); |
927 | 0 | parameters.MessageEnd(); |
928 | 0 | seq.MessageEnd(); |
929 | 0 | } |
930 | | |
931 | | void GF2NPP::DEREncode(BufferedTransformation &bt) const |
932 | 0 | { |
933 | 0 | DERSequenceEncoder seq(bt); |
934 | 0 | ASN1::characteristic_two_field().DEREncode(seq); |
935 | 0 | DERSequenceEncoder parameters(seq); |
936 | 0 | DEREncodeUnsigned(parameters, m); |
937 | 0 | ASN1::ppBasis().DEREncode(parameters); |
938 | 0 | DERSequenceEncoder pentanomial(parameters); |
939 | 0 | DEREncodeUnsigned(pentanomial, t3); |
940 | 0 | DEREncodeUnsigned(pentanomial, t2); |
941 | 0 | DEREncodeUnsigned(pentanomial, t1); |
942 | 0 | pentanomial.MessageEnd(); |
943 | 0 | parameters.MessageEnd(); |
944 | 0 | seq.MessageEnd(); |
945 | 0 | } |
946 | | |
947 | | GF2NP * BERDecodeGF2NP(BufferedTransformation &bt) |
948 | 0 | { |
949 | 0 | member_ptr<GF2NP> result; |
950 | |
|
951 | 0 | BERSequenceDecoder seq(bt); |
952 | 0 | if (OID(seq) != ASN1::characteristic_two_field()) |
953 | 0 | BERDecodeError(); |
954 | 0 | BERSequenceDecoder parameters(seq); |
955 | 0 | unsigned int m; |
956 | 0 | BERDecodeUnsigned(parameters, m); |
957 | 0 | OID oid(parameters); |
958 | 0 | if (oid == ASN1::tpBasis()) |
959 | 0 | { |
960 | 0 | unsigned int t1; |
961 | 0 | BERDecodeUnsigned(parameters, t1); |
962 | 0 | result.reset(new GF2NT(m, t1, 0)); |
963 | 0 | } |
964 | 0 | else if (oid == ASN1::ppBasis()) |
965 | 0 | { |
966 | 0 | unsigned int t1, t2, t3; |
967 | 0 | BERSequenceDecoder pentanomial(parameters); |
968 | 0 | BERDecodeUnsigned(pentanomial, t3); |
969 | 0 | BERDecodeUnsigned(pentanomial, t2); |
970 | 0 | BERDecodeUnsigned(pentanomial, t1); |
971 | 0 | pentanomial.MessageEnd(); |
972 | 0 | result.reset(new GF2NPP(m, t3, t2, t1, 0)); |
973 | 0 | } |
974 | 0 | else |
975 | 0 | { |
976 | 0 | BERDecodeError(); |
977 | 0 | return NULLPTR; |
978 | 0 | } |
979 | 0 | parameters.MessageEnd(); |
980 | 0 | seq.MessageEnd(); |
981 | |
|
982 | 0 | return result.release(); |
983 | 0 | } |
984 | | |
985 | | // ******************************************************** |
986 | | |
987 | | GF2NT233::GF2NT233(unsigned int c0, unsigned int c1, unsigned int c2) |
988 | | : GF2NT(c0, c1, c2) |
989 | 0 | { |
990 | | // Asserts and checks due to Bing Shi |
991 | 0 | CRYPTOPP_ASSERT(c0 > c1 && c1 > c2 && c2==0); |
992 | | |
993 | | // The test is relaxed because of ECIES<EC2N>. The high order exponent is t0, but the other exponents are not in descending order. |
994 | 0 | if (c1 > c0 || c2 > c0) |
995 | 0 | throw InvalidArgument("GF2NT233: exponents must be in descending order"); |
996 | 0 | } |
997 | | |
998 | | const GF2NT::Element& GF2NT233::Multiply(const Element &a, const Element &b) const |
999 | 0 | { |
1000 | 0 | #if (CRYPTOPP_CLMUL_AVAILABLE) |
1001 | 0 | if (HasCLMUL()) |
1002 | 0 | { |
1003 | 0 | CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); |
1004 | 0 | CRYPTOPP_ASSERT(b.reg.size()*WORD_BITS == 256); |
1005 | 0 | CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); |
1006 | |
|
1007 | 0 | const word* pA = a.reg.begin(); |
1008 | 0 | const word* pB = b.reg.begin(); |
1009 | 0 | word* pR = result.reg.begin(); |
1010 | |
|
1011 | 0 | GF2NT_233_Multiply_Reduce_CLMUL(pA, pB, pR); |
1012 | 0 | return result; |
1013 | 0 | } |
1014 | 0 | else |
1015 | | #elif (CRYPTOPP_ARM_PMULL_AVAILABLE) |
1016 | | if (HasPMULL()) |
1017 | | { |
1018 | | CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); |
1019 | | CRYPTOPP_ASSERT(b.reg.size()*WORD_BITS == 256); |
1020 | | CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); |
1021 | | |
1022 | | const word* pA = a.reg.begin(); |
1023 | | const word* pB = b.reg.begin(); |
1024 | | word* pR = result.reg.begin(); |
1025 | | |
1026 | | GF2NT_233_Multiply_Reduce_ARMv8(pA, pB, pR); |
1027 | | return result; |
1028 | | } |
1029 | | else |
1030 | | #elif (CRYPTOPP_POWER8_VMULL_AVAILABLE) && 0 |
1031 | | if (HasPMULL()) |
1032 | | { |
1033 | | CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); |
1034 | | CRYPTOPP_ASSERT(b.reg.size()*WORD_BITS == 256); |
1035 | | CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); |
1036 | | |
1037 | | const word* pA = a.reg.begin(); |
1038 | | const word* pB = b.reg.begin(); |
1039 | | word* pR = result.reg.begin(); |
1040 | | |
1041 | | GF2NT_233_Multiply_Reduce_POWER8(pA, pB, pR); |
1042 | | return result; |
1043 | | } |
1044 | | else |
1045 | | #endif |
1046 | | |
1047 | 0 | return GF2NT::Multiply(a, b); |
1048 | 0 | } |
1049 | | |
1050 | | const GF2NT::Element& GF2NT233::Square(const Element &a) const |
1051 | 0 | { |
1052 | 0 | #if (CRYPTOPP_CLMUL_AVAILABLE) |
1053 | 0 | if (HasCLMUL()) |
1054 | 0 | { |
1055 | 0 | CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); |
1056 | 0 | CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); |
1057 | |
|
1058 | 0 | const word* pA = a.reg.begin(); |
1059 | 0 | word* pR = result.reg.begin(); |
1060 | |
|
1061 | 0 | GF2NT_233_Square_Reduce_CLMUL(pA, pR); |
1062 | 0 | return result; |
1063 | 0 | } |
1064 | 0 | else |
1065 | | #elif (CRYPTOPP_ARM_PMULL_AVAILABLE) |
1066 | | if (HasPMULL()) |
1067 | | { |
1068 | | CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); |
1069 | | CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); |
1070 | | |
1071 | | const word* pA = a.reg.begin(); |
1072 | | word* pR = result.reg.begin(); |
1073 | | |
1074 | | GF2NT_233_Square_Reduce_ARMv8(pA, pR); |
1075 | | return result; |
1076 | | } |
1077 | | else |
1078 | | #elif (CRYPTOPP_POWER8_VMULL_AVAILABLE) && 0 |
1079 | | if (HasPMULL()) |
1080 | | { |
1081 | | CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); |
1082 | | CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); |
1083 | | |
1084 | | const word* pA = a.reg.begin(); |
1085 | | word* pR = result.reg.begin(); |
1086 | | |
1087 | | GF2NT_233_Square_Reduce_POWER8(pA, pR); |
1088 | | return result; |
1089 | | } |
1090 | | else |
1091 | | #endif |
1092 | | |
1093 | 0 | return GF2NT::Square(a); |
1094 | 0 | } |
1095 | | |
1096 | | NAMESPACE_END |
1097 | | |
1098 | | #endif |