Crypto++
ec2n.cpp
1 // ec2n.cpp - 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 
10 #include "algebra.cpp"
11 #include "eprecomp.cpp"
12 
13 NAMESPACE_BEGIN(CryptoPP)
14 
16  : m_field(BERDecodeGF2NP(bt))
17 {
18  BERSequenceDecoder seq(bt);
19  m_field->BERDecodeElement(seq, m_a);
20  m_field->BERDecodeElement(seq, m_b);
21  // skip optional seed
22  if (!seq.EndReached())
23  {
24  SecByteBlock seed;
25  unsigned int unused;
26  BERDecodeBitString(seq, seed, unused);
27  }
28  seq.MessageEnd();
29 }
30 
31 void EC2N::DEREncode(BufferedTransformation &bt) const
32 {
33  m_field->DEREncode(bt);
34  DERSequenceEncoder seq(bt);
35  m_field->DEREncodeElement(seq, m_a);
36  m_field->DEREncodeElement(seq, m_b);
37  seq.MessageEnd();
38 }
39 
40 bool EC2N::DecodePoint(EC2N::Point &P, const byte *encodedPoint, size_t encodedPointLen) const
41 {
42  StringStore store(encodedPoint, encodedPointLen);
43  return DecodePoint(P, store, encodedPointLen);
44 }
45 
46 bool EC2N::DecodePoint(EC2N::Point &P, BufferedTransformation &bt, size_t encodedPointLen) const
47 {
48  byte type;
49  if (encodedPointLen < 1 || !bt.Get(type))
50  return false;
51 
52  switch (type)
53  {
54  case 0:
55  P.identity = true;
56  return true;
57  case 2:
58  case 3:
59  {
60  if (encodedPointLen != EncodedPointSize(true))
61  return false;
62 
63  P.identity = false;
64  P.x.Decode(bt, m_field->MaxElementByteLength());
65 
66  if (P.x.IsZero())
67  {
68  P.y = m_field->SquareRoot(m_b);
69  return true;
70  }
71 
72  FieldElement z = m_field->Square(P.x);
73  assert(P.x == m_field->SquareRoot(z));
74  P.y = m_field->Divide(m_field->Add(m_field->Multiply(z, m_field->Add(P.x, m_a)), m_b), z);
75  assert(P.x == m_field->Subtract(m_field->Divide(m_field->Subtract(m_field->Multiply(P.y, z), m_b), z), m_a));
76  z = m_field->SolveQuadraticEquation(P.y);
77  assert(m_field->Add(m_field->Square(z), z) == P.y);
78  z.SetCoefficient(0, type & 1);
79 
80  P.y = m_field->Multiply(z, P.x);
81  return true;
82  }
83  case 4:
84  {
85  if (encodedPointLen != EncodedPointSize(false))
86  return false;
87 
88  unsigned int len = m_field->MaxElementByteLength();
89  P.identity = false;
90  P.x.Decode(bt, len);
91  P.y.Decode(bt, len);
92  return true;
93  }
94  default:
95  return false;
96  }
97 }
98 
99 void EC2N::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const
100 {
101  if (P.identity)
102  NullStore().TransferTo(bt, EncodedPointSize(compressed));
103  else if (compressed)
104  {
105  bt.Put(2 + (!P.x ? 0 : m_field->Divide(P.y, P.x).GetBit(0)));
106  P.x.Encode(bt, m_field->MaxElementByteLength());
107  }
108  else
109  {
110  unsigned int len = m_field->MaxElementByteLength();
111  bt.Put(4); // uncompressed
112  P.x.Encode(bt, len);
113  P.y.Encode(bt, len);
114  }
115 }
116 
117 void EC2N::EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const
118 {
119  ArraySink sink(encodedPoint, EncodedPointSize(compressed));
120  EncodePoint(sink, P, compressed);
121  assert(sink.TotalPutLength() == EncodedPointSize(compressed));
122 }
123 
124 EC2N::Point EC2N::BERDecodePoint(BufferedTransformation &bt) const
125 {
126  SecByteBlock str;
127  BERDecodeOctetString(bt, str);
128  Point P;
129  if (!DecodePoint(P, str, str.size()))
130  BERDecodeError();
131  return P;
132 }
133 
134 void EC2N::DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const
135 {
136  SecByteBlock str(EncodedPointSize(compressed));
137  EncodePoint(str, P, compressed);
138  DEREncodeOctetString(bt, str);
139 }
140 
141 bool EC2N::ValidateParameters(RandomNumberGenerator &rng, unsigned int level) const
142 {
143  bool pass = !!m_b;
144  pass = pass && m_a.CoefficientCount() <= m_field->MaxElementBitLength();
145  pass = pass && m_b.CoefficientCount() <= m_field->MaxElementBitLength();
146 
147  if (level >= 1)
148  pass = pass && m_field->GetModulus().IsIrreducible();
149 
150  return pass;
151 }
152 
153 bool EC2N::VerifyPoint(const Point &P) const
154 {
155  const FieldElement &x = P.x, &y = P.y;
156  return P.identity ||
157  (x.CoefficientCount() <= m_field->MaxElementBitLength()
158  && y.CoefficientCount() <= m_field->MaxElementBitLength()
159  && !(((x+m_a)*x*x+m_b-(x+y)*y)%m_field->GetModulus()));
160 }
161 
162 bool EC2N::Equal(const Point &P, const Point &Q) const
163 {
164  if (P.identity && Q.identity)
165  return true;
166 
167  if (P.identity && !Q.identity)
168  return false;
169 
170  if (!P.identity && Q.identity)
171  return false;
172 
173  return (m_field->Equal(P.x,Q.x) && m_field->Equal(P.y,Q.y));
174 }
175 
176 const EC2N::Point& EC2N::Identity() const
177 {
178  return Singleton<Point>().Ref();
179 }
180 
181 const EC2N::Point& EC2N::Inverse(const Point &P) const
182 {
183  if (P.identity)
184  return P;
185  else
186  {
187  m_R.identity = false;
188  m_R.y = m_field->Add(P.x, P.y);
189  m_R.x = P.x;
190  return m_R;
191  }
192 }
193 
194 const EC2N::Point& EC2N::Add(const Point &P, const Point &Q) const
195 {
196  if (P.identity) return Q;
197  if (Q.identity) return P;
198  if (Equal(P, Q)) return Double(P);
199  if (m_field->Equal(P.x, Q.x) && m_field->Equal(P.y, m_field->Add(Q.x, Q.y))) return Identity();
200 
201  FieldElement t = m_field->Add(P.y, Q.y);
202  t = m_field->Divide(t, m_field->Add(P.x, Q.x));
203  FieldElement x = m_field->Square(t);
204  m_field->Accumulate(x, t);
205  m_field->Accumulate(x, Q.x);
206  m_field->Accumulate(x, m_a);
207  m_R.y = m_field->Add(P.y, m_field->Multiply(t, x));
208  m_field->Accumulate(x, P.x);
209  m_field->Accumulate(m_R.y, x);
210 
211  m_R.x.swap(x);
212  m_R.identity = false;
213  return m_R;
214 }
215 
216 const EC2N::Point& EC2N::Double(const Point &P) const
217 {
218  if (P.identity) return P;
219  if (!m_field->IsUnit(P.x)) return Identity();
220 
221  FieldElement t = m_field->Divide(P.y, P.x);
222  m_field->Accumulate(t, P.x);
223  m_R.y = m_field->Square(P.x);
224  m_R.x = m_field->Square(t);
225  m_field->Accumulate(m_R.x, t);
226  m_field->Accumulate(m_R.x, m_a);
227  m_field->Accumulate(m_R.y, m_field->Multiply(t, m_R.x));
228  m_field->Accumulate(m_R.y, m_R.x);
229 
230  m_R.identity = false;
231  return m_R;
232 }
233 
234 // ********************************************************
235 
236 /*
237 EcPrecomputation<EC2N>& EcPrecomputation<EC2N>::operator=(const EcPrecomputation<EC2N> &rhs)
238 {
239  m_ec = rhs.m_ec;
240  m_ep = rhs.m_ep;
241  m_ep.m_group = m_ec.get();
242  return *this;
243 }
244 
245 void EcPrecomputation<EC2N>::SetCurveAndBase(const EC2N &ec, const EC2N::Point &base)
246 {
247  m_ec.reset(new EC2N(ec));
248  m_ep.SetGroupAndBase(*m_ec, base);
249 }
250 
251 void EcPrecomputation<EC2N>::Precompute(unsigned int maxExpBits, unsigned int storage)
252 {
253  m_ep.Precompute(maxExpBits, storage);
254 }
255 
256 void EcPrecomputation<EC2N>::Load(BufferedTransformation &bt)
257 {
258  BERSequenceDecoder seq(bt);
259  word32 version;
260  BERDecodeUnsigned<word32>(seq, version, INTEGER, 1, 1);
261  m_ep.m_exponentBase.BERDecode(seq);
262  m_ep.m_windowSize = m_ep.m_exponentBase.BitCount() - 1;
263  m_ep.m_bases.clear();
264  while (!seq.EndReached())
265  m_ep.m_bases.push_back(m_ec->BERDecodePoint(seq));
266  seq.MessageEnd();
267 }
268 
269 void EcPrecomputation<EC2N>::Save(BufferedTransformation &bt) const
270 {
271  DERSequenceEncoder seq(bt);
272  DEREncodeUnsigned<word32>(seq, 1); // version
273  m_ep.m_exponentBase.DEREncode(seq);
274  for (unsigned i=0; i<m_ep.m_bases.size(); i++)
275  m_ec->DEREncodePoint(seq, m_ep.m_bases[i]);
276  seq.MessageEnd();
277 }
278 
279 EC2N::Point EcPrecomputation<EC2N>::Exponentiate(const Integer &exponent) const
280 {
281  return m_ep.Exponentiate(exponent);
282 }
283 
284 EC2N::Point EcPrecomputation<EC2N>::CascadeExponentiate(const Integer &exponent, const DL_FixedBasePrecomputation<Element> &pc2, const Integer &exponent2) const
285 {
286  return m_ep.CascadeExponentiate(exponent, static_cast<const EcPrecomputation<EC2N> &>(pc2).m_ep, exponent2);
287 }
288 */
289 
290 NAMESPACE_END
291 
292 #endif
a block of memory allocated using A
Definition: secblock.h:238
interface for random number generators
Definition: cryptlib.h:669
BER Sequence Decoder.
Definition: asn.h:177
interface for buffered transformations
Definition: cryptlib.h:771
Copy input to a memory buffer.
Definition: filters.h:635
empty store
Definition: filters.h:713
lword TransferTo(BufferedTransformation &target, lword transferMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL)
move transferMax bytes of the buffered output to target as input
Definition: cryptlib.h:900
size_t Put(byte inByte, bool blocking=true)
input a byte for processing
Definition: cryptlib.h:785
Elliptic Curve over GF(2^n)
Definition: ec2n.h:30
string-based implementation of Store interface
Definition: filters.h:666
DER Sequence Encoder.
Definition: asn.h:187
virtual size_t Get(byte &outByte)
try to retrieve a single byte
Definition: cryptlib.cpp:405
Elliptic Curve Point.
Definition: ec2n.h:12