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 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(ref BigInt x, ref SecureVector!word ws) const; 45 46 abstract void fromCurveRep(ref BigInt x, ref SecureVector!word ws) const; 47 48 abstract void curveMul(ref BigInt z, const ref BigInt x, const ref BigInt y, ref SecureVector!word ws) const; 49 50 abstract void curveSqr(ref BigInt z, const ref BigInt x, ref SecureVector!word ws) const; 51 52 void normalize(ref 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 79 class CurveGFpMontgomery : CurveGFpRepr 80 { 81 this()(auto const ref BigInt p, auto const ref BigInt a, auto const ref BigInt b) 82 { 83 m_p = p.dup; 84 m_a = a.dup; 85 m_b = b.dup; 86 m_p_words = m_p.sigWords(); 87 m_p_dash = montyInverse(m_p.wordAt(0)); 88 BigInt r = BigInt.powerOf2(m_p_words * BOTAN_MP_WORD_BITS); 89 m_r2 = (r * r) % m_p; 90 m_a_r = (m_a * r) % m_p; 91 m_b_r = (m_b * r) % m_p; 92 } 93 94 override ref const(BigInt) getP() const { return m_p; } 95 96 override ref const(BigInt) getA() const { return m_a; } 97 98 override ref const(BigInt) getB() const { return m_b; } 99 100 override ref const(BigInt) getARep() const { return m_a_r; } 101 102 override ref const(BigInt) getBRep() const { return m_b_r; } 103 104 override size_t getPWords() const { return m_p_words; } 105 106 override void toCurveRep(ref BigInt x, ref SecureVector!word ws) const 107 { 108 const BigInt tx = x.dup; 109 curveMul(x, tx, m_r2, ws); 110 } 111 112 override void fromCurveRep(ref BigInt x, ref SecureVector!word ws) const 113 { 114 const BigInt tx = x.dup; 115 BigInt bi = BigInt(1); 116 curveMul(x, tx, bi, ws); 117 } 118 119 /** 120 * Montgomery multiplication/reduction 121 * Notes: z cannot alias x or y 122 * Params: 123 * z = output 124 * x = first multiplicand 125 * y = second multiplicand 126 */ 127 override void curveMul(ref BigInt z, const ref BigInt x, const ref BigInt y, ref SecureVector!word ws) const 128 { 129 130 if (x.isZero() || y.isZero()) 131 { 132 z = 0; 133 return; 134 } 135 136 const size_t output_size = 2*m_p_words + 1; 137 ws.resize(2*(m_p_words+2)); 138 139 z.growTo(output_size); 140 z.clear(); 141 142 bigint_monty_mul(z.mutablePtr(), output_size, 143 x.ptr, x.length, x.sigWords(), 144 y.ptr, y.length, y.sigWords(), 145 m_p.ptr, m_p_words, m_p_dash, 146 ws.ptr); 147 } 148 149 /** 150 * Montgomery squaring/reduction 151 * Notes: z cannot alias x 152 * Params: 153 * z = output 154 * x = multiplicand 155 */ 156 override void curveSqr(ref BigInt z, const ref BigInt x, ref SecureVector!word ws) const 157 { 158 if (x.isZero()) 159 { 160 z = 0; 161 return; 162 } 163 164 const size_t output_size = 2*m_p_words + 1; 165 ws.resize(2*(m_p_words+2)); 166 167 z.growTo(output_size); 168 z.clear(); 169 bigint_monty_sqr(z.mutablePtr(), output_size, 170 x.ptr, x.length, x.sigWords(), 171 m_p.ptr, m_p_words, m_p_dash, 172 ws.ptr); 173 } 174 175 override Vector!char toVector() const 176 { 177 Vector!char ret; 178 ret ~= "m_p: "; 179 ret ~= m_p.toString(); 180 ret ~= "\nm_a: "; 181 ret ~= m_a.toString(); 182 ret ~= "\nm_b: "; 183 ret ~= m_b.toString(); 184 ret ~= "\nm_r2: "; 185 ret ~= m_r2.toString(); 186 ret ~= "\nm_a_r: "; 187 ret ~= m_a_r.toString(); 188 ret ~= "\nm_b_r: "; 189 ret ~= m_b_r.toString(); 190 ret ~= "\nm_p_dash: "; 191 ret ~= m_p_dash.to!string; 192 ret ~= "\nm_p_words: "; 193 ret ~= m_p_words.to!string; 194 ret ~= "\n"; 195 return ret.move(); 196 } 197 198 private: 199 // Curve parameters 200 BigInt m_p, m_a, m_b; 201 202 size_t m_p_words; // cache of m_p.sigWords() 203 204 // Montgomery parameters 205 BigInt m_r2, m_a_r, m_b_r; 206 word m_p_dash; 207 208 } 209 210 /** 211 * This class represents an elliptic curve over GF(p) 212 */ 213 struct CurveGFp 214 { 215 /** 216 * Construct the elliptic curve E: y^2 = x^3 + ax + b over GF(p) 217 * Params: 218 * p = prime number of the field 219 * a = first coefficient 220 * b = second coefficient 221 */ 222 this()(auto const ref BigInt p, auto const ref BigInt a, auto const ref BigInt b) 223 { 224 m_repr = chooseRepr(p, a, b); 225 } 226 227 /** 228 * Returns: curve coefficient a 229 */ 230 ref const(BigInt) getA() const { return m_repr.getA(); } 231 232 /** 233 * Returns: curve coefficient b 234 */ 235 ref const(BigInt) getB() const { return m_repr.getB(); } 236 237 /** 238 * Get prime modulus of the field of the curve 239 * Returns: prime modulus of the field of the curve 240 */ 241 ref const(BigInt) getP() const { return m_repr.getP(); } 242 243 /** 244 * Returns: a * r mod p 245 */ 246 ref const(BigInt) getARep() const { return m_repr.getARep(); } 247 248 /** 249 * Returns: b * r mod p 250 */ 251 ref const(BigInt) getBRep() const { return m_repr.getBRep(); } 252 253 void toRep()(ref BigInt x, SecureVector!word* ws) const 254 { 255 m_repr.toCurveRep(x, *ws); 256 } 257 258 void fromRep(ref BigInt x, SecureVector!word* ws) const 259 { 260 m_repr.fromCurveRep(x, *ws); 261 } 262 263 BigInt fromRep()(auto const ref BigInt x, SecureVector!word* ws) const 264 { 265 BigInt xt = x.dup; 266 m_repr.fromCurveRep(xt, *ws); 267 return xt.move; 268 } 269 270 /** 271 * swaps the states of this and other, does not throw 272 * Params: 273 * other = curve to swap values with 274 */ 275 void swap()(auto ref CurveGFp other) 276 { 277 .swap(m_repr, other.m_repr); 278 } 279 280 /** 281 * Equality operator 282 * Params: 283 * other = curve to compare with 284 * Returns: true iff this is the same curve as other 285 */ 286 bool opEquals(const ref CurveGFp other) const 287 { 288 return (getP() == other.getP() && 289 getA() == other.getA() && 290 getB() == other.getB()); 291 } 292 293 /** 294 * Equality operator 295 * Params: 296 * rhs = a curve 297 * Returns: true iff lhs is not the same as rhs 298 */ 299 int opCmp(ref CurveGFp rhs) const 300 { 301 if (this == rhs) return 0; 302 else return -1; 303 } 304 305 @property CurveGFp dup() const { 306 return CurveGFp(getP(), getA(), getB()); 307 } 308 309 // TODO: fromRep taking && ref 310 311 void mul()(ref BigInt z, auto const ref BigInt x, auto const ref BigInt y, SecureVector!word* ws) const 312 { 313 m_repr.curveMul(z, x, y, *ws); 314 } 315 316 BigInt mul()(auto const ref BigInt x, auto const ref BigInt y, SecureVector!word* ws) const 317 { 318 BigInt z; 319 m_repr.curveMul(z, x, y, *ws); 320 return z.move; 321 } 322 323 void sqr()(auto ref BigInt z, auto const ref BigInt x, SecureVector!word* ws) const 324 { 325 m_repr.curveSqr(z, x, *ws); 326 } 327 328 BigInt sqr()(auto const ref BigInt x, SecureVector!word* ws) const 329 { 330 BigInt z; 331 m_repr.curveSqr(z, x, *ws); 332 return z.move; 333 } 334 335 /** 336 * Adjust x to be in [0,p) 337 * @param bound if greater than zero, assume that no more than bound 338 * additions or subtractions are required to move x into range. 339 */ 340 void normalize(ref BigInt x, SecureVector!word* ws, size_t bound = 0) const 341 { 342 m_repr.normalize(x, *ws, bound); 343 } 344 345 @disable this(this); 346 347 string toString() const { 348 return toVector()[].idup; 349 } 350 351 Vector!char toVector() const { 352 return m_repr.toVector(); 353 } 354 355 ~this() { 356 } 357 358 static CurveGFpRepr chooseRepr()(auto const ref BigInt p, auto const ref BigInt a, auto const ref BigInt b) 359 { 360 //if (p == CurveGFpP521.prime) 361 // return cast(CurveGFpRepr) new CurveGFpP521(a, b); 362 return cast(CurveGFpRepr) new CurveGFpMontgomery(p, a, b); 363 } 364 365 Unique!CurveGFpRepr m_repr; 366 }