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.dup; 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.dup; 99 PointGFp p_r2 = r2.dup; 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.dup; 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().dup; 181 182 // get a copy 183 PointGFp q = p.dup; 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.dup; 228 229 mixin( CHECK(` p1.getAffineX() == BigInt("16984103820118642236896513183038186009872590470") `) ); 230 mixin( CHECK(` p1.getAffineY() == BigInt("1373093393927139016463695321221277758035357890939") `) ); 231 232 PointGFp p1_neg = p1.negate().dup; 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.dup; 341 p_G *= BigInt(2); 342 PointGFp p1 = p_G.dup; 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.dup; 378 p_G *= BigInt(2); 379 PointGFp p1 = p_G.dup; 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.dup; 414 p_G *= BigInt(2); 415 PointGFp p1 = p_G.dup; 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.dup; 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.dup; 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().dup; 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().dup; 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.dup; 765 PointGFp d = b.dup; 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.dup; 791 792 c *= scal.dup; 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().dup; 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 }