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() return const;
31     
32     abstract ref const(BigInt) getA() return const;
33     
34     abstract ref const(BigInt) getB() return const;
35 
36     abstract size_t getPWords() const;
37 
38     /// Returns toCurveRep(getA())
39     abstract ref const(BigInt) getARep() return const;
40 
41     /// Returns toCurveRep(getB())
42     abstract ref const(BigInt) getBRep() return 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.clone;
109         m_a = a.clone;
110         m_b = b.clone;
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 { return m_p; }
131 
132     override ref const(BigInt) getA() const return { return m_a; }
133 
134     override ref const(BigInt) getB() const return { return m_b; }
135         
136     override ref const(BigInt) getARep() const return { return m_a_r; }
137 
138     override ref const(BigInt) getBRep() const return { 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.clone;
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.clone;
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 { return m_repr.getA(); }
311 
312     /**
313     * Returns: curve coefficient b
314     */
315     ref const(BigInt) getB() const return { 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 { return m_repr.getP(); }
322 
323     /**
324     * Returns: a * r mod p
325     */
326     ref const(BigInt) getARep() const return { return m_repr.getARep(); }
327 
328     /**
329     * Returns: b * r mod p
330     */
331     ref const(BigInt) getBRep() const return { 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.clone;
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 clone() const {
396         BigInt p = getP().clone;
397         BigInt a = getA().clone;
398         BigInt b = getB().clone;
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 }