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 }