1 /** 2 * Elliptic curves over GF(p) 3 * 4 * Copyright: 5 * (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke 6 * 2010-2011,2012,2014 Jack Lloyd 7 * (C) 2014-2015 Etienne Cimon 8 * 9 * License: 10 * Botan is released under the Simplified BSD License (see LICENSE.md) 11 */ 12 module botan.math.ec_gfp.curve_gfp; 13 14 import botan.constants; 15 static if (BOTAN_HAS_PUBLIC_KEY_CRYPTO): 16 17 import botan.math.numbertheory.numthry; 18 import botan.math.mp.mp_types; 19 import botan.math.mp.mp_core; 20 import botan.math.ec_gfp.curve_nistp; 21 import std.algorithm : swap; 22 import botan.constants; 23 import memutils.unique; 24 import std.conv : to; 25 import core.stdc..string; 26 abstract class CurveGFpRepr 27 { 28 public: 29 30 abstract ref const(BigInt) getP() const; 31 32 abstract ref const(BigInt) getA() const; 33 34 abstract ref const(BigInt) getB() const; 35 36 abstract size_t getPWords() const; 37 38 /// Returns toCurveRep(getA()) 39 abstract ref const(BigInt) getARep() const; 40 41 /// Returns toCurveRep(getB()) 42 abstract ref const(BigInt) getBRep() const; 43 44 abstract void toCurveRep(BigInt* x, ref SecureVector!word ws) const; 45 46 abstract void fromCurveRep(BigInt* x, ref SecureVector!word ws) const; 47 48 abstract void curveMul(BigInt* z, const(BigInt)* x, const(BigInt)* y, ref SecureVector!word ws) const; 49 50 abstract void curveSqr(BigInt* z, const(BigInt)* x, ref SecureVector!word ws) const; 51 52 void normalize(BigInt* x, ref SecureVector!word ws, size_t bound) const { 53 const(BigInt)* p = &getP(); 54 55 while(x.isNegative()) 56 *x += *p; 57 58 const size_t p_words = getPWords(); 59 const word* prime = p.ptr; 60 61 x.growTo(p_words + 1); 62 63 if (ws.length < p_words + 1) 64 ws.resize(p_words + 1); 65 66 //FIXME: take into account bound if > 0 67 while(true) 68 { 69 if (bigint_sub3(ws.ptr, x.ptr, p_words, prime, p_words)) // borrow? 70 break; 71 72 x.swapReg(ws); 73 } 74 } 75 76 abstract Vector!char toVector() const; 77 78 abstract void swap(CurveGFpRepr); 79 } 80 81 class CurveGFpMontgomery : CurveGFpRepr 82 { 83 84 static if (BOTAN_HAS_ENGINE_OPENSSL) { 85 import deimos.openssl.bn; 86 ~this() { 87 m_p_bn.d = null; m_p_bn.top = cast(int)0; 88 m_x_.d = null; m_x_.top = cast(int)0; 89 m_y_.d = null; m_y_.top = cast(int)0; 90 m_z_.d = null; m_z_.top = cast(int)0; 91 BN_free(m_z_); 92 BN_free(m_y_); 93 BN_free(m_x_); 94 BN_free(m_p_bn); 95 BN_CTX_free(m_ctx); 96 BN_MONT_CTX_free(m_mont); 97 } 98 BIGNUM* m_z_; 99 BIGNUM* m_x_; 100 BIGNUM* m_y_; 101 BIGNUM* m_p_bn; 102 BN_CTX* m_ctx; 103 BN_MONT_CTX* m_mont; 104 } 105 106 this()(BigInt* p, BigInt* a, BigInt* b) 107 { 108 m_p = p.dup; 109 m_a = a.dup; 110 m_b = b.dup; 111 m_p_words = m_p.sigWords(); 112 m_p_dash = montyInverse(m_p.wordAt(0)); 113 BigInt r = BigInt.powerOf2(m_p_words * BOTAN_MP_WORD_BITS); 114 m_r2 = (r * r) % m_p; 115 m_a_r = (m_a * r) % m_p; 116 m_b_r = (m_b * r) % m_p; 117 static if (BOTAN_HAS_ENGINE_OPENSSL) { 118 m_z_ = BN_new(); 119 m_x_ = BN_new(); 120 m_y_ = BN_new(); 121 m_p_bn = BN_new(); 122 m_p_bn.d = cast(BN_ULONG*)m_p.ptr; 123 m_p_bn.top = cast(int)m_p.sigWords(); 124 m_ctx = BN_CTX_new(); 125 m_mont = BN_MONT_CTX_new(); 126 BN_MONT_CTX_set(m_mont, m_p_bn, m_ctx); 127 } 128 } 129 130 override ref const(BigInt) getP() const { return m_p; } 131 132 override ref const(BigInt) getA() const { return m_a; } 133 134 override ref const(BigInt) getB() const { return m_b; } 135 136 override ref const(BigInt) getARep() const { return m_a_r; } 137 138 override ref const(BigInt) getBRep() const { return m_b_r; } 139 140 override size_t getPWords() const { return m_p_words; } 141 142 override void toCurveRep(BigInt* x, ref SecureVector!word ws) const 143 { 144 const BigInt tx = x.dup; 145 curveMul(x, &tx, &m_r2, ws); 146 } 147 148 override void fromCurveRep(BigInt* x, ref SecureVector!word ws) const 149 { 150 const BigInt tx = x.dup; 151 BigInt bi = BigInt(1); 152 curveMul(x, &tx, &bi, ws); 153 } 154 155 /** 156 * Montgomery multiplication/reduction 157 * Notes: z cannot alias x or y 158 * Params: 159 * z = output 160 * x = first multiplicand 161 * y = second multiplicand 162 */ 163 override void curveMul(BigInt* z, const(BigInt)* x, const(BigInt)* y, ref SecureVector!word ws) const 164 { 165 166 if (x.isZero() || y.isZero()) 167 { 168 BigInt zero = BigInt(0); 169 z.swap(&zero); 170 return; 171 } 172 173 const size_t output_size = 2*m_p_words + 1; 174 175 z.growTo(output_size); 176 z.clear(); 177 178 static if (BOTAN_HAS_ENGINE_OPENSSL) { 179 // about 2-3x faster than the optimized botan-math 180 CurveGFpMontgomery this_ = cast()this; 181 this_.m_x_.neg = cast(int)0; 182 this_.m_x_.d = cast(BN_ULONG*)x.ptr; 183 this_.m_x_.top = cast(int) x.sigWords(); 184 this_.m_y_.neg = cast(int)0; 185 this_.m_y_.d = cast(BN_ULONG*)y.ptr; 186 this_.m_y_.top = cast(int) y.sigWords(); 187 BN_CTX* ctx_ = BN_CTX_new(); 188 scope(exit) BN_CTX_free(ctx_); 189 BN_mod_mul_montgomery(this_.m_z_, this_.m_x_, this_.m_y_, this_.m_mont, ctx_); 190 memcpy(cast(ubyte*)z.mutablePtr(), cast(ubyte*)this_.m_z_.d, cast(ubyte*)(this_.m_z_.top*word.sizeof)); 191 } 192 else { 193 ws.resize(2*(m_p_words+2)); 194 bigint_monty_mul(z.mutablePtr(), output_size, 195 x.ptr, x.length, x.sigWords(), 196 y.ptr, y.length, y.sigWords(), 197 m_p.ptr, m_p_words, m_p_dash, 198 ws.ptr); 199 } 200 } 201 202 /** 203 * Montgomery squaring/reduction 204 * Notes: z cannot alias x 205 * Params: 206 * z = output 207 * x = multiplicand 208 */ 209 override void curveSqr(BigInt* z, const(BigInt)* x, ref SecureVector!word ws) const 210 { 211 if (x.isZero()) 212 { 213 BigInt zero = BigInt(0); 214 z.swap(&zero); 215 return; 216 } 217 const size_t output_size = 2*m_p_words + 1; 218 z.growTo(output_size); 219 z.clear(); 220 static if (BOTAN_HAS_ENGINE_OPENSSL) { 221 // about 2-3x faster than the optimized botan-math 222 CurveGFpMontgomery this_ = cast()this; 223 this_.m_x_.neg = cast(int)0; 224 this_.m_x_.d = cast(BN_ULONG*)x.ptr; 225 this_.m_x_.top = cast(int) x.sigWords(); 226 BN_CTX* ctx_ = BN_CTX_new(); 227 scope(exit) BN_CTX_free(ctx_); 228 BN_mod_mul_montgomery(this_.m_z_, this_.m_x_, this_.m_x_, this_.m_mont, ctx_); 229 memcpy(cast(ubyte*)z.mutablePtr(), cast(ubyte*)this_.m_z_.d, cast(ubyte*)(this_.m_z_.top*word.sizeof)); 230 } 231 else { 232 ws.resize(2*(m_p_words+2)); 233 234 bigint_monty_sqr(z.mutablePtr(), output_size, 235 x.ptr, x.length, x.sigWords(), 236 m_p.ptr, m_p_words, m_p_dash, 237 ws.ptr); 238 } 239 } 240 241 override Vector!char toVector() const 242 { 243 Vector!char ret; 244 ret ~= "m_p: "; 245 ret ~= m_p.toString(); 246 ret ~= "\nm_a: "; 247 ret ~= m_a.toString(); 248 ret ~= "\nm_b: "; 249 ret ~= m_b.toString(); 250 ret ~= "\nm_r2: "; 251 ret ~= m_r2.toString(); 252 ret ~= "\nm_a_r: "; 253 ret ~= m_a_r.toString(); 254 ret ~= "\nm_b_r: "; 255 ret ~= m_b_r.toString(); 256 ret ~= "\nm_p_dash: "; 257 ret ~= m_p_dash.to!string; 258 ret ~= "\nm_p_words: "; 259 ret ~= m_p_words.to!string; 260 ret ~= "\n"; 261 return ret.move(); 262 } 263 264 override void swap(CurveGFpRepr other_) 265 { 266 auto other = cast(CurveGFpMontgomery) other_; 267 m_p.swap(&other.m_p); 268 m_a.swap(&other.m_a); 269 m_b.swap(&other.m_b); 270 m_r2.swap(&other.m_r2); 271 m_a_r.swap(&other.m_a_r); 272 m_b_r.swap(&other.m_b_r); 273 import std.algorithm.mutation : swap; 274 swap(m_p_words, other.m_p_words); 275 swap(m_p_dash, other.m_p_dash); 276 } 277 278 private: 279 // Curve parameters 280 BigInt m_p, m_a, m_b; 281 282 size_t m_p_words; // cache of m_p.sigWords() 283 284 // Montgomery parameters 285 BigInt m_r2, m_a_r, m_b_r; 286 word m_p_dash; 287 288 } 289 290 /** 291 * This class represents an elliptic curve over GF(p) 292 */ 293 struct CurveGFp 294 { 295 /** 296 * Construct the elliptic curve E: y^2 = x^3 + ax + b over GF(p) 297 * Params: 298 * p = prime number of the field 299 * a = first coefficient 300 * b = second coefficient 301 */ 302 this()(BigInt* p, BigInt* a, BigInt* b) 303 { 304 m_repr = chooseRepr(p, a, b); 305 } 306 307 /** 308 * Returns: curve coefficient a 309 */ 310 ref const(BigInt) getA() const { return m_repr.getA(); } 311 312 /** 313 * Returns: curve coefficient b 314 */ 315 ref const(BigInt) getB() const { return m_repr.getB(); } 316 317 /** 318 * Get prime modulus of the field of the curve 319 * Returns: prime modulus of the field of the curve 320 */ 321 ref const(BigInt) getP() const { return m_repr.getP(); } 322 323 /** 324 * Returns: a * r mod p 325 */ 326 ref const(BigInt) getARep() const { return m_repr.getARep(); } 327 328 /** 329 * Returns: b * r mod p 330 */ 331 ref const(BigInt) getBRep() const { return m_repr.getBRep(); } 332 333 void toRep()(BigInt* x, SecureVector!word ws) const 334 { 335 m_repr.toCurveRep(x, ws); 336 } 337 338 void toRep()(BigInt* x, ref SecureVector!word ws) const 339 { 340 m_repr.toCurveRep(x, ws); 341 } 342 343 void fromRep(BigInt* x, SecureVector!word ws) const 344 { 345 m_repr.fromCurveRep(x, ws); 346 } 347 348 void fromRep(BigInt* x, ref SecureVector!word ws) const 349 { 350 m_repr.fromCurveRep(x, ws); 351 } 352 353 BigInt fromRep()(const(BigInt)* x, ref SecureVector!word ws) const 354 { 355 BigInt xt = x.dup; 356 m_repr.fromCurveRep(&xt, ws); 357 return xt.move; 358 } 359 360 /** 361 * swaps the states of this and other, does not throw 362 * Params: 363 * other = curve to swap values with 364 */ 365 void swap(T)(T other) 366 { 367 .swap(m_repr, other.m_repr); 368 } 369 370 /** 371 * Equality operator 372 * Params: 373 * other = curve to compare with 374 * Returns: true iff this is the same curve as other 375 */ 376 bool opEquals(const ref CurveGFp other) const 377 { 378 return (getP() == other.getP() && 379 getA() == other.getA() && 380 getB() == other.getB()); 381 } 382 383 /** 384 * Equality operator 385 * Params: 386 * rhs = a curve 387 * Returns: true iff lhs is not the same as rhs 388 */ 389 int opCmp(ref CurveGFp rhs) const 390 { 391 if (this == rhs) return 0; 392 else return -1; 393 } 394 395 @property CurveGFp dup() const { 396 BigInt p = getP().dup; 397 BigInt a = getA().dup; 398 BigInt b = getB().dup; 399 return CurveGFp(&p, &a, &b); 400 } 401 402 // TODO: fromRep taking && ref 403 404 void mul()(BigInt* z, const(BigInt)* x, const(BigInt*) y, SecureVector!word ws) const 405 { 406 m_repr.curveMul(z, x, y, ws); 407 } 408 409 BigInt mul()(const(BigInt)* x, const(BigInt*) y, SecureVector!word ws) const 410 { 411 BigInt z; 412 m_repr.curveMul(z, x, y, ws); 413 return z.move; 414 } 415 416 void sqr()(BigInt* z, const(BigInt)* x, SecureVector!word ws) const 417 { 418 m_repr.curveSqr(z, x, ws); 419 } 420 421 BigInt sqr()(const(BigInt)* x, SecureVector!word ws) const 422 { 423 BigInt z; 424 m_repr.curveSqr(z, x, ws); 425 return z.move; 426 } 427 428 /** 429 * Adjust x to be in [0,p) 430 * @param bound if greater than zero, assume that no more than bound 431 * additions or subtractions are required to move x into range. 432 */ 433 void normalize(BigInt* x, ref SecureVector!word ws, size_t bound = 0) const 434 { 435 m_repr.normalize(x, ws, bound); 436 } 437 438 @disable this(this); 439 440 string toString() const { 441 return toVector()[].idup; 442 } 443 444 Vector!char toVector() const { 445 return m_repr.toVector(); 446 } 447 448 static CurveGFpRepr chooseRepr()(BigInt* p, BigInt* a, BigInt* b) 449 { 450 //if (p == CurveGFpP521.prime) 451 // return cast(CurveGFpRepr) new CurveGFpP521(a, b); 452 return cast(CurveGFpRepr) new CurveGFpMontgomery(p, a, b); 453 } 454 455 Unique!CurveGFpRepr m_repr; 456 }