Coverage Report

Created: 2024-11-21 07:03

/src/cryptopp/ec2n.cpp
Line
Count
Source (jump to first uncovered line)
1
// ec2n.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 "ec2n.h"
8
#include "asn.h"
9
#include "integer.h"
10
#include "filters.h"
11
#include "algebra.cpp"
12
#include "eprecomp.cpp"
13
14
ANONYMOUS_NAMESPACE_BEGIN
15
16
using CryptoPP::EC2N;
17
18
#if defined(HAVE_GCC_INIT_PRIORITY)
19
  #define INIT_ATTRIBUTE __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 51)))
20
  const EC2N::Point g_identity INIT_ATTRIBUTE = EC2N::Point();
21
#elif defined(HAVE_MSC_INIT_PRIORITY)
22
  #pragma warning(disable: 4075)
23
  #pragma init_seg(".CRT$XCU")
24
  const EC2N::Point g_identity;
25
  #pragma warning(default: 4075)
26
#elif defined(HAVE_XLC_INIT_PRIORITY)
27
  #pragma priority(290)
28
  const EC2N::Point g_identity;
29
#endif
30
31
ANONYMOUS_NAMESPACE_END
32
33
NAMESPACE_BEGIN(CryptoPP)
34
35
EC2N::EC2N(BufferedTransformation &bt)
36
  : m_field(BERDecodeGF2NP(bt))
37
0
{
38
0
  BERSequenceDecoder seq(bt);
39
0
  m_field->BERDecodeElement(seq, m_a);
40
0
  m_field->BERDecodeElement(seq, m_b);
41
  // skip optional seed
42
0
  if (!seq.EndReached())
43
0
  {
44
0
    SecByteBlock seed;
45
0
    unsigned int unused;
46
0
    BERDecodeBitString(seq, seed, unused);
47
0
  }
48
0
  seq.MessageEnd();
49
0
}
50
51
void EC2N::DEREncode(BufferedTransformation &bt) const
52
0
{
53
0
  m_field->DEREncode(bt);
54
0
  DERSequenceEncoder seq(bt);
55
0
     m_field->DEREncodeElement(seq, m_a);
56
0
     m_field->DEREncodeElement(seq, m_b);
57
0
  seq.MessageEnd();
58
0
}
59
60
bool EC2N::DecodePoint(EC2N::Point &P, const byte *encodedPoint, size_t encodedPointLen) const
61
0
{
62
0
  StringStore store(encodedPoint, encodedPointLen);
63
0
  return DecodePoint(P, store, encodedPointLen);
64
0
}
65
66
bool EC2N::DecodePoint(EC2N::Point &P, BufferedTransformation &bt, size_t encodedPointLen) const
67
0
{
68
0
  byte type;
69
0
  if (encodedPointLen < 1 || !bt.Get(type))
70
0
    return false;
71
72
0
  switch (type)
73
0
  {
74
0
  case 0:
75
0
    P.identity = true;
76
0
    return true;
77
0
  case 2:
78
0
  case 3:
79
0
  {
80
0
    if (encodedPointLen != EncodedPointSize(true))
81
0
      return false;
82
83
0
    P.identity = false;
84
0
    P.x.Decode(bt, m_field->MaxElementByteLength());
85
86
0
    if (P.x.IsZero())
87
0
    {
88
0
      P.y = m_field->SquareRoot(m_b);
89
0
      return true;
90
0
    }
91
92
0
    FieldElement z = m_field->Square(P.x);
93
0
    CRYPTOPP_ASSERT(P.x == m_field->SquareRoot(z));
94
0
    P.y = m_field->Divide(m_field->Add(m_field->Multiply(z, m_field->Add(P.x, m_a)), m_b), z);
95
0
    CRYPTOPP_ASSERT(P.x == m_field->Subtract(m_field->Divide(m_field->Subtract(m_field->Multiply(P.y, z), m_b), z), m_a));
96
0
    z = m_field->SolveQuadraticEquation(P.y);
97
0
    CRYPTOPP_ASSERT(m_field->Add(m_field->Square(z), z) == P.y);
98
0
    z.SetCoefficient(0, type & 1);
99
100
0
    P.y = m_field->Multiply(z, P.x);
101
0
    return true;
102
0
  }
103
0
  case 4:
104
0
  {
105
0
    if (encodedPointLen != EncodedPointSize(false))
106
0
      return false;
107
108
0
    unsigned int len = m_field->MaxElementByteLength();
109
0
    P.identity = false;
110
0
    P.x.Decode(bt, len);
111
0
    P.y.Decode(bt, len);
112
0
    return true;
113
0
  }
114
0
  default:
115
0
    return false;
116
0
  }
117
0
}
118
119
void EC2N::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const
120
0
{
121
0
  if (P.identity)
122
0
    NullStore().TransferTo(bt, EncodedPointSize(compressed));
123
0
  else if (compressed)
124
0
  {
125
0
    bt.Put((byte)(2U + (!P.x ? 0U : m_field->Divide(P.y, P.x).GetBit(0))));
126
0
    P.x.Encode(bt, m_field->MaxElementByteLength());
127
0
  }
128
0
  else
129
0
  {
130
0
    unsigned int len = m_field->MaxElementByteLength();
131
0
    bt.Put(4);  // uncompressed
132
0
    P.x.Encode(bt, len);
133
0
    P.y.Encode(bt, len);
134
0
  }
135
0
}
136
137
void EC2N::EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const
138
0
{
139
0
  ArraySink sink(encodedPoint, EncodedPointSize(compressed));
140
0
  EncodePoint(sink, P, compressed);
141
0
  CRYPTOPP_ASSERT(sink.TotalPutLength() == EncodedPointSize(compressed));
142
0
}
143
144
EC2N::Point EC2N::BERDecodePoint(BufferedTransformation &bt) const
145
0
{
146
0
  SecByteBlock str;
147
0
  BERDecodeOctetString(bt, str);
148
0
  Point P;
149
0
  if (!DecodePoint(P, str, str.size()))
150
0
    BERDecodeError();
151
0
  return P;
152
0
}
153
154
void EC2N::DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const
155
0
{
156
0
  SecByteBlock str(EncodedPointSize(compressed));
157
0
  EncodePoint(str, P, compressed);
158
0
  DEREncodeOctetString(bt, str);
159
0
}
160
161
bool EC2N::ValidateParameters(RandomNumberGenerator &rng, unsigned int level) const
162
0
{
163
0
  CRYPTOPP_UNUSED(rng);
164
0
  bool pass = !!m_b;
165
0
  pass = pass && m_a.CoefficientCount() <= m_field->MaxElementBitLength();
166
0
  pass = pass && m_b.CoefficientCount() <= m_field->MaxElementBitLength();
167
168
0
  if (level >= 1)
169
0
    pass = pass && m_field->GetModulus().IsIrreducible();
170
171
0
  return pass;
172
0
}
173
174
bool EC2N::VerifyPoint(const Point &P) const
175
0
{
176
0
  const FieldElement &x = P.x, &y = P.y;
177
0
  return P.identity ||
178
0
    (x.CoefficientCount() <= m_field->MaxElementBitLength()
179
0
    && y.CoefficientCount() <= m_field->MaxElementBitLength()
180
0
    && !(((x+m_a)*x*x+m_b-(x+y)*y)%m_field->GetModulus()));
181
0
}
182
183
bool EC2N::Equal(const Point &P, const Point &Q) const
184
0
{
185
0
  if (P.identity && Q.identity)
186
0
    return true;
187
188
0
  if (P.identity && !Q.identity)
189
0
    return false;
190
191
0
  if (!P.identity && Q.identity)
192
0
    return false;
193
194
0
  return (m_field->Equal(P.x,Q.x) && m_field->Equal(P.y,Q.y));
195
0
}
196
197
const EC2N::Point& EC2N::Identity() const
198
0
{
199
0
#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY) || defined(HAVE_XLC_INIT_PRIORITY)
200
0
  return g_identity;
201
#elif defined(CRYPTOPP_CXX11_STATIC_INIT)
202
  static const EC2N::Point g_identity;
203
  return g_identity;
204
#else
205
  return Singleton<Point>().Ref();
206
#endif
207
0
}
208
209
const EC2N::Point& EC2N::Inverse(const Point &P) const
210
0
{
211
0
  if (P.identity)
212
0
    return P;
213
0
  else
214
0
  {
215
0
    m_R.identity = false;
216
0
    m_R.y = m_field->Add(P.x, P.y);
217
0
    m_R.x = P.x;
218
0
    return m_R;
219
0
  }
220
0
}
221
222
const EC2N::Point& EC2N::Add(const Point &P, const Point &Q) const
223
0
{
224
0
  if (P.identity) return Q;
225
0
  if (Q.identity) return P;
226
0
  if (Equal(P, Q)) return Double(P);
227
0
  if (m_field->Equal(P.x, Q.x) && m_field->Equal(P.y, m_field->Add(Q.x, Q.y))) return Identity();
228
229
0
  FieldElement t = m_field->Add(P.y, Q.y);
230
0
  t = m_field->Divide(t, m_field->Add(P.x, Q.x));
231
0
  FieldElement x = m_field->Square(t);
232
0
  m_field->Accumulate(x, t);
233
0
  m_field->Accumulate(x, Q.x);
234
0
  m_field->Accumulate(x, m_a);
235
0
  m_R.y = m_field->Add(P.y, m_field->Multiply(t, x));
236
0
  m_field->Accumulate(x, P.x);
237
0
  m_field->Accumulate(m_R.y, x);
238
239
0
  m_R.x.swap(x);
240
0
  m_R.identity = false;
241
0
  return m_R;
242
0
}
243
244
const EC2N::Point& EC2N::Double(const Point &P) const
245
0
{
246
0
  if (P.identity) return P;
247
0
  if (!m_field->IsUnit(P.x)) return Identity();
248
249
0
  FieldElement t = m_field->Divide(P.y, P.x);
250
0
  m_field->Accumulate(t, P.x);
251
0
  m_R.y = m_field->Square(P.x);
252
0
  m_R.x = m_field->Square(t);
253
0
  m_field->Accumulate(m_R.x, t);
254
0
  m_field->Accumulate(m_R.x, m_a);
255
0
  m_field->Accumulate(m_R.y, m_field->Multiply(t, m_R.x));
256
0
  m_field->Accumulate(m_R.y, m_R.x);
257
258
0
  m_R.identity = false;
259
0
  return m_R;
260
0
}
261
262
// ********************************************************
263
264
#if 0
265
EcPrecomputation<EC2N>& EcPrecomputation<EC2N>::operator=(const EcPrecomputation<EC2N> &rhs)
266
{
267
  m_ec = rhs.m_ec;
268
  m_ep = rhs.m_ep;
269
  m_ep.m_group = m_ec.get();
270
  return *this;
271
}
272
273
void EcPrecomputation<EC2N>::SetCurveAndBase(const EC2N &ec, const EC2N::Point &base)
274
{
275
  m_ec.reset(new EC2N(ec));
276
  m_ep.SetGroupAndBase(*m_ec, base);
277
}
278
279
void EcPrecomputation<EC2N>::Precompute(unsigned int maxExpBits, unsigned int storage)
280
{
281
  m_ep.Precompute(maxExpBits, storage);
282
}
283
284
void EcPrecomputation<EC2N>::Load(BufferedTransformation &bt)
285
{
286
  BERSequenceDecoder seq(bt);
287
  word32 version;
288
  BERDecodeUnsigned<word32>(seq, version, INTEGER, 1, 1);
289
  m_ep.m_exponentBase.BERDecode(seq);
290
  m_ep.m_windowSize = m_ep.m_exponentBase.BitCount() - 1;
291
  m_ep.m_bases.clear();
292
  while (!seq.EndReached())
293
    m_ep.m_bases.push_back(m_ec->BERDecodePoint(seq));
294
  seq.MessageEnd();
295
}
296
297
void EcPrecomputation<EC2N>::Save(BufferedTransformation &bt) const
298
{
299
  DERSequenceEncoder seq(bt);
300
  DEREncodeUnsigned<word32>(seq, 1);  // version
301
  m_ep.m_exponentBase.DEREncode(seq);
302
  for (unsigned i=0; i<m_ep.m_bases.size(); i++)
303
    m_ec->DEREncodePoint(seq, m_ep.m_bases[i]);
304
  seq.MessageEnd();
305
}
306
307
EC2N::Point EcPrecomputation<EC2N>::Exponentiate(const Integer &exponent) const
308
{
309
  return m_ep.Exponentiate(exponent);
310
}
311
312
EC2N::Point EcPrecomputation<EC2N>::CascadeExponentiate(const Integer &exponent, const DL_FixedBasePrecomputation<Element> &pc2, const Integer &exponent2) const
313
{
314
  return m_ep.CascadeExponentiate(exponent, static_cast<const EcPrecomputation<EC2N> &>(pc2).m_ep, exponent2);
315
}
316
#endif
317
318
NAMESPACE_END
319
320
#endif