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