1 /**
2 * Unit test helper
3 * 
4 * Copyright:
5 * (C) 2014-2015 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.math.ec_gfp.test;
12 
13 import botan.constants;
14 static if (BOTAN_TEST && BOTAN_HAS_PUBLIC_KEY_CRYPTO):
15 
16 import botan.test;
17 
18 import botan.codec.hex;
19 import botan.rng.auto_rng;
20 import botan.math.numbertheory.numthry;
21 import botan.math.ec_gfp.curve_gfp;
22 import botan.math.ec_gfp.point_gfp;
23 import botan.pubkey.algo.ec_group;
24 import botan.math.numbertheory.reducer;
25 import botan.asn1.oids;
26 import botan.utils.types;
27 import botan.utils.mem_ops;
28 
29 size_t total_tests;
30 
31 string toString(PointGFp point) {
32     Vector!char output;
33     output ~= "(" ~ point.getAffineX().toString() ~ " " ~ point.getAffineY().toString() ~ " )";
34     return output[].idup;
35 }
36 
37 PointGFp createRandomPoint(RandomNumberGenerator rng, const ref CurveGFp curve)
38 {
39     const BigInt* p = &curve.getP();
40     
41     ModularReducer mod_p = ModularReducer(*p);
42     
43     while(true)
44     {
45         BigInt x = BigInt(rng, p.bits());
46         
47         auto x_2 = mod_p.square(&x);
48 
49         BigInt x3 = mod_p.multiply(&x, &x_2);
50         
51         BigInt ax = mod_p.multiply(&curve.getA(), &x);
52 
53         BigInt bx3 = mod_p.multiply(&curve.getB(), &x3);
54         
55         BigInt y = mod_p.reduce(ax + bx3);
56         
57         if (ressol(&y, p) > 0)
58             return PointGFp(curve, &x, &y);
59     }
60 }
61 
62 size_t testPointTurnOnSpRedMul()
63 {
64     size_t fails = 0;
65     
66     // setting up expected values
67     BigInt exp_Qx = BigInt("466448783855397898016055842232266600516272889280");
68     BigInt exp_Qy = BigInt("1110706324081757720403272427311003102474457754220");
69     BigInt exp_Qz = BigInt(1);
70     
71     // performing calculation to test
72     string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
73     string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
74     string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
75     string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
76     Vector!ubyte sv_p_secp = hexDecode(p_secp);
77     Vector!ubyte sv_a_secp = hexDecode(a_secp);
78     Vector!ubyte sv_b_secp = hexDecode(b_secp);
79     Vector!ubyte sv_G_secp_comp = hexDecode(G_secp_comp);
80     BigInt bi_p_secp = BigInt.decode(sv_p_secp.ptr, sv_p_secp.length);
81     BigInt bi_a_secp = BigInt.decode(sv_a_secp.ptr, sv_a_secp.length);
82     BigInt bi_b_secp = BigInt.decode(sv_b_secp.ptr, sv_b_secp.length);
83     CurveGFp secp160r1 = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
84     PointGFp p_G = OS2ECP(sv_G_secp_comp, secp160r1);
85     
86     BigInt d = BigInt("459183204582304");
87     
88     PointGFp r1 = p_G * &d;
89     mixin( CHECK(` r1.getAffineX() != 0 `) );
90     
91     PointGFp p_G2 = p_G.clone;
92     
93     PointGFp r2 = p_G2 * &d;
94 
95     mixin( CHECK_MESSAGE( `r1 == r2`, "error with point mul after extra turn on sp red mul" ) );
96     mixin( CHECK(` r1.getAffineX() != 0 `) );
97     
98     PointGFp p_r1 = r1.clone;
99     PointGFp p_r2 = r2.clone;
100     
101     p_r1 *= BigInt(2);
102     p_r2 *= BigInt(2);
103     mixin( CHECK_MESSAGE( `p_r1.getAffineX() == p_r2.getAffineX()`, "error with mult2 after extra turn on sp red mul" ) );
104     mixin( CHECK(` p_r1.getAffineX() != 0 `) );
105     mixin( CHECK(` p_r2.getAffineX() != 0 `) );
106     r1 *= BigInt(2);    
107     r2 *= BigInt(2);
108     
109     mixin( CHECK_MESSAGE( `r1 == r2`, "error with mult2 after extra turn on sp red mul" ) );
110     mixin( CHECK_MESSAGE( `r1.getAffineX() == r2.getAffineX()`, "error with mult2 after extra turn on sp red mul" ) );
111     mixin( CHECK(` r1.getAffineX() != 0 `) );
112     r1 += p_G;
113     r2 += p_G2;
114     
115     mixin( CHECK_MESSAGE( `r1 == r2`, "error with op+= after extra turn on sp red mul" ) );
116     
117     r1 += p_G;
118     r2 += p_G2;
119     
120     mixin( CHECK_MESSAGE( `r1 == r2`, "error with op+= after extra turn on sp red mul for both operands" ) );
121     r1 += p_G;
122     r2 += p_G2;
123     
124     mixin( CHECK_MESSAGE( `r1 == r2`, "error with op+= after extra turn on sp red mul for both operands" ) );
125     return fails;
126 }
127 
128 size_t testCoordinates()
129 {
130     size_t fails = 0;
131     
132     BigInt exp_affine_x = BigInt("16984103820118642236896513183038186009872590470");
133     BigInt exp_affine_y = BigInt("1373093393927139016463695321221277758035357890939");
134     
135     // precalculation
136     string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
137     string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
138     string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
139     string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
140     Vector!ubyte sv_p_secp = hexDecode( p_secp );
141     Vector!ubyte sv_a_secp = hexDecode( a_secp );
142     Vector!ubyte sv_b_secp = hexDecode( b_secp );
143     Vector!ubyte sv_G_secp_comp = hexDecode( G_secp_comp );
144     
145     BigInt bi_p_secp = BigInt.decode( sv_p_secp.ptr, sv_p_secp.length );
146     BigInt bi_a_secp = BigInt.decode( sv_a_secp.ptr, sv_a_secp.length );
147     BigInt bi_b_secp = BigInt.decode( sv_b_secp.ptr, sv_b_secp.length );
148     CurveGFp secp160r1 = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
149     PointGFp p_G = OS2ECP( sv_G_secp_comp, secp160r1 );
150     PointGFp p0 = p_G.clone;
151     PointGFp p1 = p_G * BigInt(2);
152     PointGFp point_exp = PointGFp(secp160r1, &exp_affine_x, &exp_affine_y);
153     if (!point_exp.onTheCurve())
154         throw new InternalError("Point not on the curve");
155     
156     mixin( CHECK_MESSAGE(  `p1.getAffineX() == exp_affine_x`, " p1_x = ` ~ p1.getAffineX().toString() ~ ` \n` ~ `exp_x = ` ~ exp_affine_x.toString() ~ ` \n" ) );
157     mixin( CHECK_MESSAGE(  `p1.getAffineY() == exp_affine_y`, " p1_y = ` ~ p1.getAffineY().toString() ~ ` \n` ~ `exp_y = ` ~ exp_affine_y.toString() ~ ` \n" ) );
158     return fails;
159 }
160 
161 
162 /**
163 Test point multiplication according to
164 --------
165 SEC 2: Test Vectors for SEC 1
166 Certicom Research
167 Working Draft
168 September, 1999
169 Version 0.3;
170 Section 2.1.2
171 --------
172 */
173 
174 size_t testPointTransformation ()
175 {
176     size_t fails = 0;
177     
178     // get a vailid point
179     ECGroup dom_pars = ECGroup(OID("1.3.132.0.8"));
180     PointGFp p = dom_pars.getBasePoint().clone;
181     
182     // get a copy
183     PointGFp q = p.clone;
184     
185     mixin( CHECK_MESSAGE(  `p.getAffineX() == q.getAffineX()`, "affine_x changed during copy" ) );
186     mixin( CHECK_MESSAGE(  `p.getAffineY() == q.getAffineY()`, "affine_y changed during copy" ) );
187     return fails;
188 }
189 
190 size_t testPointMult ()
191 {
192     size_t fails = 0;
193     
194     ECGroup secp160r1 = ECGroup(OIDS.lookup("secp160r1"));
195         
196     string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
197     Vector!ubyte sv_G_secp_comp = hexDecode(G_secp_comp);
198     PointGFp p_G = OS2ECP(sv_G_secp_comp, secp160r1.getCurve());
199     
200     BigInt d_U = BigInt("0xaa374ffc3ce144e6b073307972cb6d57b2a4e982");
201     PointGFp Q_U = p_G * &d_U;
202     
203     mixin( CHECK(` Q_U.getAffineX() == BigInt("466448783855397898016055842232266600516272889280") `) );
204     mixin( CHECK(` Q_U.getAffineY() == BigInt("1110706324081757720403272427311003102474457754220") `) );
205     return fails;
206 }
207 
208 size_t testPointNegative()
209 {
210     size_t fails = 0;
211     
212     // performing calculation to test
213     string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
214     string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
215     string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
216     string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
217     Vector!ubyte sv_p_secp = hexDecode( p_secp );
218     Vector!ubyte sv_a_secp = hexDecode( a_secp );
219     Vector!ubyte sv_b_secp = hexDecode( b_secp );
220     Vector!ubyte sv_G_secp_comp = hexDecode( G_secp_comp );
221     BigInt bi_p_secp = BigInt.decode( sv_p_secp.ptr, sv_p_secp.length );
222     BigInt bi_a_secp = BigInt.decode( sv_a_secp.ptr, sv_a_secp.length );
223     BigInt bi_b_secp = BigInt.decode( sv_b_secp.ptr, sv_b_secp.length );
224     CurveGFp secp160r1 = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
225     PointGFp p_G = OS2ECP( sv_G_secp_comp, secp160r1 );
226     p_G *= BigInt(2);
227     PointGFp p1 = p_G.clone;
228     
229     mixin( CHECK(` p1.getAffineX() == BigInt("16984103820118642236896513183038186009872590470") `) );
230     mixin( CHECK(` p1.getAffineY() == BigInt("1373093393927139016463695321221277758035357890939") `) );
231     
232     PointGFp p1_neg = p1.negate().clone;
233     
234     mixin( CHECK(` p1_neg.getAffineX() == BigInt("16984103820118642236896513183038186009872590470") `) );
235     mixin( CHECK(` p1_neg.getAffineY() == BigInt("88408243403763901739989511495005261618427168388") `) );
236     return fails;
237 }
238 
239 size_t testZeropoint()
240 {
241     size_t fails = 0;
242     
243     string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
244     Vector!ubyte sv_G_secp_comp = hexDecode( G_secp_comp );
245     BigInt bi_p_secp = BigInt("0xffffffffffffffffffffffffffffffff7fffffff");
246     BigInt bi_a_secp = BigInt("0xffffffffffffffffffffffffffffffff7ffffffc");
247     BigInt bi_b_secp = BigInt("0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45");
248     CurveGFp secp160r1 = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
249     auto bi1 = BigInt("16984103820118642236896513183038186009872590470");
250     auto bi2 = BigInt("1373093393927139016463695321221277758035357890939");
251     PointGFp p1 = PointGFp(secp160r1, &bi1, &bi2);
252     
253     if (!p1.onTheCurve())
254         throw new InternalError("Point not on the curve");
255     p1 -= p1;
256     
257     mixin( CHECK_MESSAGE( `p1.isZero()`, "p - q with q = p is not zero!" ) );
258     return fails;
259 }
260 
261 size_t testZeropointEncDec()
262 {
263     size_t fails = 0;
264     
265     BigInt bi_p_secp = BigInt("0xffffffffffffffffffffffffffffffff7fffffff");
266     BigInt bi_a_secp = BigInt("0xffffffffffffffffffffffffffffffff7ffffffc");
267     BigInt bi_b_secp = BigInt("0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45");
268     CurveGFp curve = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
269     
270     PointGFp p = PointGFp(curve);
271     mixin( CHECK_MESSAGE( `p.isZero()`, "by constructor created zeropoint is no zeropoint!" ) );
272     
273     
274     Vector!ubyte sv_p = unlock(EC2OSP(p, PointGFp.UNCOMPRESSED));
275     PointGFp p_encdec = OS2ECP(sv_p, curve);
276     mixin( CHECK_MESSAGE( `p == p_encdec`, "encoded-decoded (uncompressed) point is not equal the original!" ) );
277     
278     sv_p = unlock(EC2OSP(p, PointGFp.UNCOMPRESSED));
279     p_encdec = OS2ECP(sv_p, curve);
280     mixin( CHECK_MESSAGE( `p == p_encdec`, "encoded-decoded (compressed) point is not equal the original!" ) );
281     
282     sv_p = unlock(EC2OSP(p, PointGFp.HYBRID));
283     p_encdec = OS2ECP(sv_p, curve);
284     mixin( CHECK_MESSAGE( `p == p_encdec`, "encoded-decoded (hybrid) point is not equal the original!" ) );
285     return fails;
286 }
287 
288 size_t testCalcWithZeropoint()
289 {
290     size_t fails = 0;
291     
292     string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
293     Vector!ubyte sv_G_secp_comp = hexDecode( G_secp_comp );
294     BigInt bi_p_secp = BigInt("0xffffffffffffffffffffffffffffffff7fffffff");
295     BigInt bi_a_secp = BigInt("0xffffffffffffffffffffffffffffffff7ffffffc");
296     BigInt bi_b_secp = BigInt("0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45");
297     CurveGFp curve = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
298     
299     auto bi1 = BigInt("16984103820118642236896513183038186009872590470");
300     auto bi2 = BigInt("1373093393927139016463695321221277758035357890939");
301     PointGFp p = PointGFp(curve, &bi1, &bi2);
302     
303     if (!p.onTheCurve())
304         throw new InternalError("Point not on the curve");
305     mixin( CHECK_MESSAGE( `!p.isZero()`, "created is zeropoint, shouldn't be!" ) );
306     
307     PointGFp zero = PointGFp(curve);
308     mixin( CHECK_MESSAGE( `zero.isZero()`, "by constructor created zeropoint is no zeropoint!" ) );
309     
310     PointGFp res = p + zero;
311     mixin( CHECK_MESSAGE( `res == p`, "point + zeropoint is not equal the point" ) );
312     
313     res = p - zero;
314     mixin( CHECK_MESSAGE( `res == p`, "point - zeropoint is not equal the point" ) );
315     
316     res = zero * BigInt(32432243);
317     mixin( CHECK_MESSAGE( `res.isZero()`, "zeropoint * skalar is not a zero-point!" ) );
318     return fails;
319 }
320 
321 size_t testAddPoint()
322 {
323     size_t fails = 0;
324     
325     // precalculation
326     string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
327     string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
328     string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
329     string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
330     Vector!ubyte sv_p_secp = hexDecode( p_secp );
331     Vector!ubyte sv_a_secp = hexDecode( a_secp );
332     Vector!ubyte sv_b_secp = hexDecode( b_secp );
333     Vector!ubyte sv_G_secp_comp = hexDecode( G_secp_comp );
334     BigInt bi_p_secp = BigInt.decode( sv_p_secp.ptr, sv_p_secp.length );
335     BigInt bi_a_secp = BigInt.decode( sv_a_secp.ptr, sv_a_secp.length );
336     BigInt bi_b_secp = BigInt.decode( sv_b_secp.ptr, sv_b_secp.length );
337     CurveGFp secp160r1 = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
338     PointGFp p_G = OS2ECP( sv_G_secp_comp, secp160r1 );
339     
340     PointGFp p0 = p_G.clone;
341     p_G *= BigInt(2);
342     PointGFp p1 = p_G.clone;
343     
344     p1 += p0;
345     auto bi1 = BigInt("704859595002530890444080436569091156047721708633");
346     auto bi2 = BigInt("1147993098458695153857594941635310323215433166682");
347     PointGFp expected = PointGFp(secp160r1, &bi1, &bi2);
348     
349     mixin( CHECK(` p1 == expected `) );
350     return fails;
351 }
352 
353 size_t testSubPoint()
354 {
355     size_t fails = 0;
356     
357     //Setting up expected values
358     BigInt exp_sub_x = BigInt("112913490230515010376958384252467223283065196552");
359     BigInt exp_sub_y = BigInt("143464803917389475471159193867377888720776527730");
360     BigInt exp_sub_z = BigInt("562006223742588575209908669014372619804457947208");
361     
362     // precalculation
363     string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
364     string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
365     string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
366     string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
367     Vector!ubyte sv_p_secp = hexDecode( p_secp );
368     Vector!ubyte sv_a_secp = hexDecode( a_secp );
369     Vector!ubyte sv_b_secp = hexDecode( b_secp );
370     Vector!ubyte sv_G_secp_comp = hexDecode( G_secp_comp );
371     BigInt bi_p_secp = BigInt.decode( sv_p_secp.ptr, sv_p_secp.length );
372     BigInt bi_a_secp = BigInt.decode( sv_a_secp.ptr, sv_a_secp.length );
373     BigInt bi_b_secp = BigInt.decode( sv_b_secp.ptr, sv_b_secp.length );
374     CurveGFp secp160r1 = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
375     PointGFp p_G = OS2ECP( sv_G_secp_comp, secp160r1 );
376     
377     PointGFp p0 = p_G.clone;
378     p_G *= BigInt(2);
379     PointGFp p1 = p_G.clone;
380     
381     p1 -= p0;
382     auto bi1 = BigInt("425826231723888350446541592701409065913635568770");
383     auto bi2 = BigInt("203520114162904107873991457957346892027982641970");
384     PointGFp expected = PointGFp(secp160r1, &bi1, &bi2);
385     
386     mixin( CHECK(` p1 == expected `) );
387     return fails;
388 }
389 
390 size_t testMultPoint()
391 {
392     size_t fails = 0;
393     
394     //Setting up expected values
395     BigInt exp_mult_x = BigInt("967697346845926834906555988570157345422864716250");
396     BigInt exp_mult_y = BigInt("512319768365374654866290830075237814703869061656");
397     
398     // precalculation
399     string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
400     string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
401     string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
402     string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
403     Vector!ubyte sv_p_secp = hexDecode( p_secp );
404     Vector!ubyte sv_a_secp = hexDecode( a_secp );
405     Vector!ubyte sv_b_secp = hexDecode( b_secp );
406     Vector!ubyte sv_G_secp_comp = hexDecode( G_secp_comp );
407     BigInt bi_p_secp = BigInt.decode( sv_p_secp.ptr, sv_p_secp.length );
408     BigInt bi_a_secp = BigInt.decode( sv_a_secp.ptr, sv_a_secp.length );
409     BigInt bi_b_secp = BigInt.decode( sv_b_secp.ptr, sv_b_secp.length );
410     CurveGFp secp160r1 = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
411     PointGFp p_G = OS2ECP( sv_G_secp_comp, secp160r1 );
412     
413     PointGFp p0 = p_G.clone;
414     p_G *= BigInt(2);
415     PointGFp p1 = p_G.clone;
416     
417     p1 *= p0.getAffineX();
418     
419     PointGFp expected = PointGFp(secp160r1, &exp_mult_x, &exp_mult_y);
420     
421     mixin( CHECK(` p1 == expected `) );
422     return fails;
423 }
424 
425 size_t testBasicOperations()
426 {
427     size_t fails = 0;
428     
429     // precalculation
430     string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
431     string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
432     string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
433     string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
434     Vector!ubyte sv_p_secp = hexDecode( p_secp );
435     Vector!ubyte sv_a_secp = hexDecode( a_secp );
436     Vector!ubyte sv_b_secp = hexDecode( b_secp );
437     Vector!ubyte sv_G_secp_comp = hexDecode( G_secp_comp );
438     BigInt bi_p_secp = BigInt.decode( sv_p_secp.ptr, sv_p_secp.length );
439     BigInt bi_a_secp = BigInt.decode( sv_a_secp.ptr, sv_a_secp.length );
440     BigInt bi_b_secp = BigInt.decode( sv_b_secp.ptr, sv_b_secp.length );
441     CurveGFp secp160r1 = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
442     
443     PointGFp p_G = OS2ECP( sv_G_secp_comp, secp160r1 );
444     
445     PointGFp p0 = p_G.clone;
446     
447     BigInt bi1 = BigInt("425826231723888350446541592701409065913635568770");
448     BigInt bi2 = BigInt("203520114162904107873991457957346892027982641970");
449     PointGFp expected = PointGFp(secp160r1, &bi1, &bi2);
450     
451     mixin( CHECK(` p0 == expected `) );
452     p_G *= BigInt(2);
453     PointGFp p1 = p_G.clone;
454     
455     mixin( CHECK(` p1.getAffineX() == BigInt("16984103820118642236896513183038186009872590470") `) );
456     mixin( CHECK(` p1.getAffineY() == BigInt("1373093393927139016463695321221277758035357890939") `) );
457     
458     PointGFp simplePlus = p1 + p0;
459 
460     bi1 = BigInt("704859595002530890444080436569091156047721708633");
461     bi2 = BigInt("1147993098458695153857594941635310323215433166682");
462     PointGFp exp_simplePlus = PointGFp(secp160r1, &bi1, &bi2);
463     if (simplePlus != exp_simplePlus)
464         logTrace(simplePlus.toString() ~ " != " ~ exp_simplePlus.toString());
465     
466     PointGFp simpleMinus= p1 - p0;
467     bi1 = BigInt("425826231723888350446541592701409065913635568770");
468     bi2 = BigInt("203520114162904107873991457957346892027982641970");
469     PointGFp exp_simpleMinus = PointGFp(secp160r1, &bi1, &bi2);
470     
471     mixin( CHECK(` simpleMinus == exp_simpleMinus `) );
472     
473     PointGFp simpleMult= p1 * BigInt(123456789);
474     
475     mixin( CHECK(` simpleMult.getAffineX() == BigInt("43638877777452195295055270548491599621118743290") `) );
476     mixin( CHECK(` simpleMult.getAffineY() == BigInt("56841378500012376527163928510402662349220202981") `) );
477     
478     // check that all initial points hasn't changed
479     mixin( CHECK(` p1.getAffineX() == BigInt("16984103820118642236896513183038186009872590470") `) );
480     mixin( CHECK(` p1.getAffineY() == BigInt("1373093393927139016463695321221277758035357890939") `) );
481     
482     mixin( CHECK(` p0.getAffineX() == BigInt("425826231723888350446541592701409065913635568770") `) );
483     mixin( CHECK(` p0.getAffineY() == BigInt("203520114162904107873991457957346892027982641970") `) );
484     return fails;
485 }
486 
487 size_t testEncDecCompressed160()
488 {
489     size_t fails = 0;
490     
491     // Test for compressed conversion (02/03) 160bit
492     string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
493     string a_secp = "ffffffffffffffffffffffffffffffff7ffffffC";
494     string b_secp = "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45";
495     string G_secp_comp = "024A96B5688EF573284664698968C38BB913CBFC82";
496     string G_order_secp_comp = "0100000000000000000001F4C8F927AED3CA752257";
497     
498     Vector!ubyte sv_p_secp = hexDecode( p_secp );
499     Vector!ubyte sv_a_secp = hexDecode( a_secp );
500     Vector!ubyte sv_b_secp = hexDecode( b_secp );
501     Vector!ubyte sv_G_secp_comp = hexDecode( G_secp_comp );
502     
503     BigInt bi_p_secp = BigInt.decode( sv_p_secp.ptr, sv_p_secp.length );
504     BigInt bi_a_secp = BigInt.decode( sv_a_secp.ptr, sv_a_secp.length );
505     BigInt bi_b_secp = BigInt.decode( sv_b_secp.ptr, sv_b_secp.length );
506     
507     CurveGFp secp160r1 = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
508     
509     PointGFp p_G = OS2ECP( sv_G_secp_comp, secp160r1 );
510     Vector!ubyte sv_result = unlock(EC2OSP(p_G, PointGFp.COMPRESSED));
511     
512     mixin( CHECK(`  sv_result == sv_G_secp_comp `) );
513     return fails;
514 }
515 
516 size_t testEncDecCompressed256()
517 {
518     size_t fails = 0;
519     
520     // Test for compressed conversion (02/03) 256bit
521     string p_secp = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff";
522     string a_secp = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffFC";
523     string b_secp = "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B";
524     string G_secp_comp = "036B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296";
525     string G_order_secp_comp = "ffffffff00000000ffffffffffffffffBCE6FAADA7179E84F3B9CAC2FC632551";
526     
527     Vector!ubyte sv_p_secp = hexDecode( p_secp );
528     Vector!ubyte sv_a_secp = hexDecode( a_secp );
529     Vector!ubyte sv_b_secp = hexDecode( b_secp );
530     Vector!ubyte sv_G_secp_comp = hexDecode( G_secp_comp );
531     
532     BigInt bi_p_secp = BigInt.decode( sv_p_secp.ptr, sv_p_secp.length );
533     BigInt bi_a_secp = BigInt.decode( sv_a_secp.ptr, sv_a_secp.length );
534     BigInt bi_b_secp = BigInt.decode( sv_b_secp.ptr, sv_b_secp.length );
535     
536     CurveGFp curve = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
537     
538     PointGFp p_G = OS2ECP( sv_G_secp_comp, curve );
539     Vector!ubyte sv_result = unlock(EC2OSP(p_G, PointGFp.COMPRESSED));
540     
541     mixin( CHECK(`  sv_result == sv_G_secp_comp `) );
542     return fails;
543 }
544 
545 
546 size_t testEncDecUncompressed112()
547 {
548     size_t fails = 0;
549     
550     // Test for uncompressed conversion (04) 112bit
551     
552     string p_secp = "db7c2abf62e35e668076bead208b";
553     string a_secp = "6127C24C05F38A0AAAF65C0EF02C";
554     string b_secp = "51DEF1815DB5ED74FCC34C85D709";
555     string G_secp_uncomp = "044BA30AB5E892B4E1649DD0928643ADCD46F5882E3747DEF36E956E97";
556     string G_order_secp_uncomp = "36DF0AAFD8B8D7597CA10520D04B";
557     
558     Vector!ubyte sv_p_secp = hexDecode( p_secp );
559     Vector!ubyte sv_a_secp = hexDecode( a_secp );
560     Vector!ubyte sv_b_secp = hexDecode( b_secp );
561     Vector!ubyte sv_G_secp_uncomp = hexDecode( G_secp_uncomp );
562     
563     BigInt bi_p_secp = BigInt.decode( sv_p_secp.ptr, sv_p_secp.length );
564     BigInt bi_a_secp = BigInt.decode( sv_a_secp.ptr, sv_a_secp.length );
565     BigInt bi_b_secp = BigInt.decode( sv_b_secp.ptr, sv_b_secp.length );
566     
567     CurveGFp curve = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
568     
569     PointGFp p_G = OS2ECP( sv_G_secp_uncomp, curve );
570     Vector!ubyte sv_result = unlock(EC2OSP(p_G, PointGFp.UNCOMPRESSED));
571     
572     mixin( CHECK(` sv_result == sv_G_secp_uncomp `) );
573     return fails;
574 }
575 
576 size_t testEncDecUncompressed521()
577 {
578     size_t fails = 0;
579     
580     // Test for uncompressed conversion(04) with big values(521 bit)
581     string p_secp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
582     string a_secp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFC";
583     string b_secp = "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00";
584     string G_secp_uncomp = "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2ffA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650";
585     string G_order_secp_uncomp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409";
586     
587     Vector!ubyte sv_p_secp = hexDecode( p_secp );
588     Vector!ubyte sv_a_secp = hexDecode( a_secp );
589     Vector!ubyte sv_b_secp = hexDecode( b_secp );
590     Vector!ubyte sv_G_secp_uncomp = hexDecode( G_secp_uncomp );
591     
592     BigInt bi_p_secp = BigInt.decode( sv_p_secp.ptr, sv_p_secp.length );
593     BigInt bi_a_secp = BigInt.decode( sv_a_secp.ptr, sv_a_secp.length );
594     BigInt bi_b_secp = BigInt.decode( sv_b_secp.ptr, sv_b_secp.length );
595     
596     CurveGFp curve = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
597     
598     PointGFp p_G = OS2ECP( sv_G_secp_uncomp, curve );
599     
600     Vector!ubyte sv_result = unlock(EC2OSP(p_G, PointGFp.UNCOMPRESSED));
601     string result = hexEncode(sv_result.ptr, sv_result.length);
602     string exp_result = hexEncode(&sv_G_secp_uncomp[0], sv_G_secp_uncomp.length);
603     
604     mixin( CHECK_MESSAGE(  `sv_result == sv_G_secp_uncomp`, "\ncalc. result = ` ~ result ~ `\nexp. result = ` ~ exp_result ~ ` \n" ) );
605     return fails;
606 }
607 
608 size_t testEncDecUncompressed521PrimeTooLarge()
609 {
610     size_t fails = 0;
611     
612     // Test for uncompressed conversion(04) with big values(521 bit)
613     string p_secp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; // length increased by "ff"
614     string a_secp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFC";
615     string b_secp = "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00";
616     string G_secp_uncomp = "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2ffA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650";
617     string G_order_secp_uncomp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409";
618     
619     Vector!ubyte sv_p_secp = hexDecode( p_secp );
620     Vector!ubyte sv_a_secp = hexDecode( a_secp );
621 
622     Vector!ubyte sv_b_secp = hexDecode( b_secp );
623     Vector!ubyte sv_G_secp_uncomp = hexDecode( G_secp_uncomp );
624     
625     BigInt bi_p_secp = BigInt.decode( sv_p_secp.ptr, sv_p_secp.length );
626     BigInt bi_a_secp = BigInt.decode( sv_a_secp.ptr, sv_a_secp.length );
627     BigInt bi_b_secp = BigInt.decode( sv_b_secp.ptr, sv_b_secp.length );
628     
629     bool exc = false;
630     try
631     {
632         PointGFp p_G;
633         CurveGFp secp521r1 = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
634         auto os2ecp = OS2ECP(sv_G_secp_uncomp, secp521r1);
635         p_G = os2ecp.move();
636         if (!p_G.onTheCurve())
637             throw new InternalError("Point not on the curve");
638     }
639     catch (Exception e)
640     {
641         exc = true;
642     }
643     
644     mixin( CHECK_MESSAGE( `exc`, "attempt of creation of point on curve with too high prime did not throw an exception" ) );
645     return fails;
646 }
647 
648 size_t testGfpStoreRestore()
649 {
650     size_t fails = 0;
651     
652     // generate point
653     //ECGroup dom_pars = global_config().get_ec_dompar("1.3.132.0.8");
654     //ECGroup dom_pars = ECGroup("1.3.132.0.8");
655     ECGroup dom_pars = ECGroup(OID("1.3.132.0.8"));
656     PointGFp p = dom_pars.getBasePoint().clone;
657     
658     //store point (to string)
659     Vector!ubyte sv_mes = unlock(EC2OSP(p, PointGFp.COMPRESSED));
660     PointGFp new_p = OS2ECP(sv_mes, dom_pars.getCurve());
661     
662     mixin( CHECK_MESSAGE(  `p == new_p`, "original and restored point are different!" ) );
663     return fails;
664 }
665 
666 
667 // maybe move this test
668 size_t testCdcCurve33()
669 {
670     size_t fails = 0;
671     
672     string G_secp_uncomp = "04081523d03d4f12cd02879dea4bf6a4f3a7df26ed888f10c5b2235a1274c386a2f218300dee6ed217841164533bcdc903f07a096f9fbf4ee95bac098a111f296f5830fe5c35b3e344d5df3a2256985f64fbe6d0edcc4c61d18bef681dd399df3d0194c5a4315e012e0245ecea56365baa9e8be1f7";
673     
674     Vector!ubyte sv_G_uncomp = hexDecode( G_secp_uncomp );
675     
676     BigInt bi_p_secp = BigInt("2117607112719756483104013348936480976596328609518055062007450442679169492999007105354629105748524349829824407773719892437896937279095106809");
677     BigInt bi_a_secp = BigInt("0xa377dede6b523333d36c78e9b0eaa3bf48ce93041f6d4fc34014d08f6833807498deedd4290101c5866e8dfb589485d13357b9e78c2d7fbe9fe");
678     BigInt bi_b_secp = BigInt("0xa9acf8c8ba617777e248509bcb4717d4db346202bf9e352cd5633731dd92a51b72a4dc3b3d17c823fcc8fbda4da08f25dea89046087342595a7");
679     
680     CurveGFp curve = CurveGFp(&bi_p_secp, &bi_a_secp, &bi_b_secp);
681     PointGFp p_G = OS2ECP( sv_G_uncomp, curve);
682     bool exc = false;
683     try
684     {
685         if (!p_G.onTheCurve())
686             throw new InternalError("Point not on the curve");
687     }
688     catch (Exception)
689     {
690         exc = true;
691     }
692     mixin( CHECK(` !exc `) );
693     return fails;
694 }
695 
696 size_t testMoreZeropoint()
697 {
698     size_t fails = 0;
699     
700     // by Falko
701     
702     string G = "024a96b5688ef573284664698968c38bb913cbfc82";
703     Vector!ubyte sv_G_secp_comp = hexDecode( G );
704     BigInt bi_p = BigInt("0xffffffffffffffffffffffffffffffff7fffffff");
705     BigInt bi_a = BigInt("0xffffffffffffffffffffffffffffffff7ffffffc");
706     BigInt bi_b = BigInt("0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45");
707     CurveGFp curve = CurveGFp(&bi_p, &bi_a, &bi_b);
708     
709     auto bi1 = BigInt("16984103820118642236896513183038186009872590470");
710     auto bi2 = BigInt("1373093393927139016463695321221277758035357890939");
711     PointGFp p1 = PointGFp(curve, &bi1, &bi2);
712     
713     if (!p1.onTheCurve())
714         throw new InternalError("Point not on the curve");
715     PointGFp minus_p1 = -p1;
716     if (!minus_p1.onTheCurve())
717         throw new InternalError("Point not on the curve");
718     PointGFp shouldBeZero = p1 + minus_p1;
719     if (!shouldBeZero.onTheCurve())
720         throw new InternalError("Point not on the curve");
721     
722     BigInt y1 = p1.getAffineY();
723     y1 = curve.getP() - y1;
724     
725     CHECK_MESSAGE(`p1.getAffineX() == minus_p1.getAffineX()`,
726                   "problem with minus_p1 : x");
727     CHECK_MESSAGE(`minus_p1.getAffineY() == y1`,
728                   "problem with minus_p1 : y");
729     
730     PointGFp zero = PointGFp(curve);
731     if (!zero.onTheCurve())
732         throw new InternalError("Point not on the curve");
733     mixin( CHECK_MESSAGE( `p1 + zero == p1`, "addition of zero modified point" ) );
734     
735     mixin( CHECK_MESSAGE( `shouldBeZero.isZero()`, "p - q with q = p is not zero!" ) );
736     return fails;
737 }
738 
739 size_t testMultByOrder()
740 {
741     size_t fails = 0;
742     
743     // generate point
744     ECGroup dom_pars = ECGroup(OID("1.3.132.0.8"));
745     PointGFp p = dom_pars.getBasePoint().clone;
746     PointGFp shouldBeZero = p * &dom_pars.getOrder();
747     
748     mixin( CHECK_MESSAGE( `shouldBeZero.isZero()`, "G * order != O" ) );
749     return fails;
750 }
751 
752 size_t testPointSwap()
753 {
754     size_t fails = 0;
755     
756     ECGroup dom_pars = ECGroup(OID("1.3.132.0.8"));
757     
758 	Unique!AutoSeededRNG rng = new AutoSeededRNG;
759     
760     PointGFp a = createRandomPoint(*rng, dom_pars.getCurve());
761     PointGFp b = createRandomPoint(*rng, dom_pars.getCurve());
762     b *= BigInt(20);
763     
764     PointGFp c = a.clone;
765     PointGFp d = b.clone;
766     
767     c.swap(&d); // TODO: check this for dual swap
768     ///mixin( CHECK(` a == d `) ); disabled due to swap not being dual
769     mixin( CHECK(` b == c `) );
770     return fails;
771 }
772 
773 /**
774 * This test verifies that the side channel attack resistant multiplication function
775 * yields the same result as the normal (insecure) multiplication via operator*=
776 */
777 size_t testMultSecMass()
778 {
779     size_t fails = 0;
780     
781 	Unique!AutoSeededRNG rng = new AutoSeededRNG;
782     
783     ECGroup dom_pars = ECGroup(OID("1.3.132.0.8"));
784     for(int i = 0; i<50; i++)
785     {
786         PointGFp a = createRandomPoint(*rng, dom_pars.getCurve());
787         BigInt scal = BigInt(*rng, 40);
788         auto scal_ref = &scal;
789         PointGFp b = a * scal_ref;
790         PointGFp c = a.clone;
791         
792         c *= scal.clone;
793         mixin( CHECK(` b == c `) );
794     }
795     return fails;
796 }
797 
798 size_t testCurveCpCtor()
799 {
800     try
801     {
802         ECGroup dom_pars = ECGroup(OID("1.3.132.0.8"));
803         CurveGFp curve = dom_pars.getCurve().clone;
804     }
805     catch (Exception)
806     {
807         return 1;
808         
809     }
810     
811     return 0;
812 }
813 
814 
815 size_t randomizedTest(RandomNumberGenerator rng, const ref ECGroup group)
816 {
817 	auto b2 = BigInt(2);
818     const BigInt a = BigInt.randomInteger(rng, b2, group.getOrder());
819     const BigInt b = BigInt.randomInteger(rng, b2, group.getOrder());
820     const BigInt c = a + b;
821     
822     const PointGFp P = group.getBasePoint() * &a;
823     const PointGFp Q = group.getBasePoint() * &b;
824     const PointGFp R = group.getBasePoint() * &c;
825     
826     const PointGFp A1 = P + Q;
827     const PointGFp A2 = Q + P;
828     
829     size_t fails = 0;
830     
831     mixin( CHECK(`A1 == R`) );
832     mixin( CHECK(`A2 == R`) );
833     mixin( CHECK(`P.onTheCurve()`) );
834     mixin( CHECK(`Q.onTheCurve()`) );
835     mixin( CHECK(`R.onTheCurve()`) );
836     mixin( CHECK(`A1.onTheCurve()`) );
837     mixin( CHECK(`A2.onTheCurve()`) );
838     
839     return fails;
840 }
841 
842 size_t randomizedTest()
843 {
844 	Unique!AutoSeededRNG rng = new AutoSeededRNG;
845     size_t fails = 0;
846     
847     const string[] groups = [
848         "brainpool160r1",
849         "brainpool192r1",
850         "brainpool224r1",
851         "brainpool256r1",
852         "brainpool320r1",
853         "brainpool384r1",
854         "brainpool512r1",
855         "gost_256A",
856         "secp112r1",
857         "secp112r2",
858         "secp128r1",
859         "secp128r2",
860         "secp160k1",
861         "secp160r1",
862         "secp160r2",
863         "secp192k1",
864         "secp192r1",
865         "secp224k1",
866         "secp224r1",
867         "secp256k1",
868         "secp256r1",
869         "secp384r1",
870         "secp521r1",
871         "x962_p192v2",
872         "x962_p192v3",
873         "x962_p239v1",
874         "x962_p239v2",
875         "x962_p239v3"
876     ];
877     
878     foreach(group_name; groups)
879     {
880         ECGroup group = ECGroup(group_name);
881         
882         PointGFp inf = group.getBasePoint() * &group.getOrder();
883         mixin( CHECK(`inf.isZero()`) );
884         
885         for(size_t i = 0; i != 32; ++i)
886             fails += randomizedTest(*rng, group);
887     }
888     
889     return fails;
890 }
891 
892 static if (BOTAN_HAS_TESTS && !SKIP_EC_GFP_TEST) unittest
893 {
894     import botan.libstate.global_state;
895     auto state = globalState(); // ensure initialized
896 
897     logDebug("Testing ec_gfp/test.d ...");
898     size_t fails = 0;
899     
900     logTrace("testPointTurnOnSpRedMul");
901     fails += testPointTurnOnSpRedMul();
902     logTrace("testCoordinates");
903     fails += testCoordinates();
904     logTrace("testPointTransformation");
905     fails += testPointTransformation ();
906     logTrace("testPointMult");
907     fails += testPointMult ();
908     logTrace("testPointNegative");
909     fails += testPointNegative();
910     logTrace("testZeropoint");
911     fails += testZeropoint();
912     logTrace("testZeropointEncDec");
913     fails += testZeropointEncDec();
914     logTrace("testCalcWithZeropoint");
915     fails += testCalcWithZeropoint();
916     logTrace("testAddPoint");
917     fails += testAddPoint();
918     logTrace("testSubPoint");
919     fails += testSubPoint();
920     logTrace("testMultPoint");
921     fails += testMultPoint();
922     logTrace("testBasicOperations");
923     fails += testBasicOperations();
924     logTrace("testEncDecCompressed160");
925     fails += testEncDecCompressed160();
926     logTrace("testEncDecCompressed256");
927     fails += testEncDecCompressed256();
928     logTrace("testEncDecUncompressed112");
929     fails += testEncDecUncompressed112();
930     logTrace("testEncDecUncompressed521");
931     fails += testEncDecUncompressed521();
932     logTrace("testEncDecUncompressed521PrimeTooLarge");
933     fails += testEncDecUncompressed521PrimeTooLarge();
934     logTrace("testGfpStoreRestore");
935     fails += testGfpStoreRestore();
936     logTrace("testCdcCurve33");
937     fails += testCdcCurve33();
938     logTrace("testMoreZeropoint");
939     fails += testMoreZeropoint();
940     logTrace("testMultByOrder");
941     fails += testMultByOrder();
942     logTrace("testPointSwap");
943     fails += testPointSwap();
944     logTrace("testMultSecMass");
945     fails += testMultSecMass();
946     logTrace("testCurveCpCtor");
947     fails += testCurveCpCtor();
948     logTrace("randomizedTest");
949     fails += randomizedTest();
950 
951     testReport("ECC", total_tests, fails);
952 
953 }