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 |