Coverage Report

Created: 2024-11-21 07:03

/src/cryptopp/gf2n.cpp
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 &quotient,
361
           const PolynomialMod2 &dividend, 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