Coverage Report

Created: 2024-11-21 07:03

/src/cryptopp/ecp.cpp
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