Add cyclic group abstraction, with test code. Separate off exponentation
[u/mdw/catacomb] / ec.c
1 /* -*-c-*-
2 *
3 * $Id: ec.c,v 1.8 2004/04/01 12:50:09 mdw Exp $
4 *
5 * Elliptic curve definitions
6 *
7 * (c) 2001 Straylight/Edgeware
8 */
9
10 /*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30 /*----- Revision history --------------------------------------------------*
31 *
32 * $Log: ec.c,v $
33 * Revision 1.8 2004/04/01 12:50:09 mdw
34 * Add cyclic group abstraction, with test code. Separate off exponentation
35 * functions for better static linking. Fix a buttload of bugs on the way.
36 * Generally ensure that negative exponents do inversion correctly. Add
37 * table of standard prime-field subgroups. (Binary field subgroups are
38 * currently unimplemented but easy to add if anyone ever finds a good one.)
39 *
40 * Revision 1.7 2004/03/27 17:54:11 mdw
41 * Standard curves and curve checking.
42 *
43 * Revision 1.6 2004/03/23 15:19:32 mdw
44 * Test elliptic curves more thoroughly.
45 *
46 * Revision 1.5 2004/03/21 22:52:06 mdw
47 * Merge and close elliptic curve branch.
48 *
49 * Revision 1.4.4.2 2004/03/20 00:13:31 mdw
50 * Projective coordinates for prime curves
51 *
52 * Revision 1.4.4.1 2003/06/10 13:43:53 mdw
53 * Simple (non-projective) curves over prime fields now seem to work.
54 *
55 * Revision 1.4 2003/05/15 23:25:59 mdw
56 * Make elliptic curve stuff build.
57 *
58 * Revision 1.3 2002/01/13 13:48:44 mdw
59 * Further progress.
60 *
61 * Revision 1.2 2001/05/07 17:29:44 mdw
62 * Treat projective coordinates as an internal representation. Various
63 * minor interface changes.
64 *
65 * Revision 1.1 2001/04/29 18:12:33 mdw
66 * Prototype version.
67 *
68 */
69
70 /*----- Header files ------------------------------------------------------*/
71
72 #include "ec.h"
73
74 /*----- Trivial wrappers --------------------------------------------------*/
75
76 /* --- @ec_samep@ --- *
77 *
78 * Arguments: @ec_curve *c, *d@ = two elliptic curves
79 *
80 * Returns: Nonzero if the curves are identical (not just isomorphic).
81 *
82 * Use: Checks for sameness of curves. This function does the full
83 * check, not just the curve-type-specific check done by the
84 * @sampep@ field operation.
85 */
86
87 int ec_samep(ec_curve *c, ec_curve *d)
88 {
89 return (field_samep(c->f, d->f) && c->ops == d->ops && EC_SAMEP(c, d));
90 }
91
92 /* --- @ec_create@ --- *
93 *
94 * Arguments: @ec *p@ = pointer to an elliptic-curve point
95 *
96 * Returns: The argument @p@.
97 *
98 * Use: Initializes a new point. The initial value is the additive
99 * identity (which is universal for all curves).
100 */
101
102 ec *ec_create(ec *p) { EC_CREATE(p); return (p); }
103
104 /* --- @ec_destroy@ --- *
105 *
106 * Arguments: @ec *p@ = pointer to an elliptic-curve point
107 *
108 * Returns: ---
109 *
110 * Use: Destroys a point, making it invalid.
111 */
112
113 void ec_destroy(ec *p) { EC_DESTROY(p); }
114
115 /* --- @ec_atinf@ --- *
116 *
117 * Arguments: @const ec *p@ = pointer to a point
118 *
119 * Returns: Nonzero if %$p = O$% is the point at infinity, zero
120 * otherwise.
121 */
122
123 int ec_atinf(const ec *p) { return (EC_ATINF(p)); }
124
125 /* --- @ec_setinf@ --- *
126 *
127 * Arguments: @ec *p@ = pointer to a point
128 *
129 * Returns: The argument @p@.
130 *
131 * Use: Sets the given point to be the point %$O$% at infinity.
132 */
133
134 ec *ec_setinf(ec *p) { EC_SETINF(p); return (p); }
135
136 /* --- @ec_copy@ --- *
137 *
138 * Arguments: @ec *d@ = pointer to destination point
139 * @const ec *p@ = pointer to source point
140 *
141 * Returns: The destination @d@.
142 *
143 * Use: Creates a copy of an elliptic curve point.
144 */
145
146 ec *ec_copy(ec *d, const ec *p) { EC_COPY(d, p); return (d); }
147
148 /* --- @ec_eq@ --- *
149 *
150 * Arguments: @const ec *p, *q@ = two points
151 *
152 * Returns: Nonzero if the points are equal. Compares external-format
153 * points.
154 */
155
156 int ec_eq(const ec *p, const ec *q) { return (EC_EQ(p, q)); }
157
158 /*----- Standard curve operations -----------------------------------------*/
159
160 /* --- @ec_stdsamep@ --- *
161 *
162 * Arguments: @ec_curve *c, *d@ = two elliptic curves
163 *
164 * Returns: Nonzero if the curves are identical (not just isomorphic).
165 *
166 * Use: Simple sameness check on @a@ and @b@ curve members.
167 */
168
169 int ec_stdsamep(ec_curve *c, ec_curve *d)
170 {
171 return (MP_EQ(c->a, d->a) && MP_EQ(c->b, d->b));
172 }
173
174 /* --- @ec_idin@, @ec_idout@, @ec_idfix@ --- *
175 *
176 * Arguments: @ec_curve *c@ = pointer to an elliptic curve
177 * @ec *d@ = pointer to the destination
178 * @const ec *p@ = pointer to a source point
179 *
180 * Returns: The destination @d@.
181 *
182 * Use: An identity operation if your curve has no internal
183 * representation. (The field internal representation is still
184 * used.)
185 */
186
187 ec *ec_idin(ec_curve *c, ec *d, const ec *p)
188 {
189 if (EC_ATINF(p))
190 EC_SETINF(d);
191 else {
192 field *f = c->f;
193 d->x = F_IN(f, d->x, p->x);
194 d->y = F_IN(f, d->y, p->y);
195 mp_drop(d->z); d->z = 0;
196 }
197 return (d);
198 }
199
200 ec *ec_idout(ec_curve *c, ec *d, const ec *p)
201 {
202 if (EC_ATINF(p))
203 EC_SETINF(d);
204 else {
205 field *f = c->f;
206 d->x = F_OUT(f, d->x, p->x);
207 d->y = F_OUT(f, d->y, p->y);
208 mp_drop(d->z); d->z = 0;
209 }
210 return (d);
211 }
212
213 ec *ec_idfix(ec_curve *c, ec *d, const ec *p)
214 {
215 EC_COPY(d, p);
216 return (d);
217 }
218
219 /* --- @ec_projin@, @ec_projout@ --- *
220 *
221 * Arguments: @ec_curve *c@ = pointer to an elliptic curve
222 * @ec *d@ = pointer to the destination
223 * @const ec *p@ = pointer to a source point
224 *
225 * Returns: The destination @d@.
226 *
227 * Use: Conversion functions if your curve operations use a
228 * projective representation.
229 */
230
231 ec *ec_projin(ec_curve *c, ec *d, const ec *p)
232 {
233 if (EC_ATINF(p))
234 EC_SETINF(d);
235 else {
236 field *f = c->f;
237 d->x = F_IN(f, d->x, p->x);
238 d->y = F_IN(f, d->y, p->y);
239 mp_drop(d->z); d->z = MP_COPY(f->one);
240 }
241 return (d);
242 }
243
244 ec *ec_projout(ec_curve *c, ec *d, const ec *p)
245 {
246 if (EC_ATINF(p))
247 EC_SETINF(d);
248 else {
249 mp *x, *y, *z, *zz;
250 field *f = c->f;
251 z = F_INV(f, MP_NEW, p->z);
252 zz = F_SQR(f, MP_NEW, z);
253 z = F_MUL(f, z, zz, z);
254 x = F_MUL(f, d->x, p->x, zz);
255 y = F_MUL(f, d->y, p->y, z);
256 mp_drop(z);
257 mp_drop(zz);
258 mp_drop(d->z);
259 d->x = F_OUT(f, x, x);
260 d->y = F_OUT(f, y, y);
261 d->z = 0;
262 }
263 return (d);
264 }
265
266 ec *ec_projfix(ec_curve *c, ec *d, const ec *p)
267 {
268 if (EC_ATINF(p))
269 EC_SETINF(d);
270 else if (d->z == c->f->one)
271 EC_COPY(d, p);
272 else {
273 mp *z, *zz;
274 field *f = c->f;
275 z = F_INV(f, MP_NEW, p->z);
276 zz = F_SQR(f, MP_NEW, z);
277 z = F_MUL(f, z, zz, z);
278 d->x = F_MUL(f, d->x, p->x, zz);
279 d->y = F_MUL(f, d->y, p->y, z);
280 mp_drop(z);
281 mp_drop(zz);
282 mp_drop(d->z);
283 d->z = MP_COPY(f->one);
284 }
285 return (d);
286 }
287
288 /* --- @ec_stdsub@ --- *
289 *
290 * Arguments: @ec_curve *c@ = pointer to an elliptic curve
291 * @ec *d@ = pointer to the destination
292 * @const ec *p, *q@ = the operand points
293 *
294 * Returns: The destination @d@.
295 *
296 * Use: Standard point subtraction operation, in terms of negation
297 * and addition. This isn't as efficient as a ready-made
298 * subtraction operator.
299 */
300
301 ec *ec_stdsub(ec_curve *c, ec *d, const ec *p, const ec *q)
302 {
303 ec t = EC_INIT;
304 EC_NEG(c, &t, q);
305 EC_FIX(c, &t, &t);
306 EC_ADD(c, d, p, &t);
307 EC_DESTROY(&t);
308 return (d);
309 }
310
311 /*----- Creating curves ---------------------------------------------------*/
312
313 /* --- @ec_destroycurve@ --- *
314 *
315 * Arguments: @ec_curve *c@ = pointer to an ellptic curve
316 *
317 * Returns: ---
318 *
319 * Use: Destroys a description of an elliptic curve.
320 */
321
322 void ec_destroycurve(ec_curve *c) { c->ops->destroy(c); }
323
324 /*----- Real arithmetic ---------------------------------------------------*/
325
326 /* --- @ec_find@ --- *
327 *
328 * Arguments: @ec_curve *c@ = pointer to an elliptic curve
329 * @ec *d@ = pointer to the destination point
330 * @mp *x@ = a possible x-coordinate
331 *
332 * Returns: Zero if OK, nonzero if there isn't a point there.
333 *
334 * Use: Finds a point on an elliptic curve with a given x-coordinate.
335 */
336
337 ec *ec_find(ec_curve *c, ec *d, mp *x)
338 {
339 x = F_IN(c->f, MP_NEW, x);
340 if ((d = EC_FIND(c, d, x)) != 0)
341 EC_OUT(c, d, d);
342 MP_DROP(x);
343 return (d);
344 }
345
346 /* --- @ec_neg@ --- *
347 *
348 * Arguments: @ec_curve *c@ = pointer to an elliptic curve
349 * @ec *d@ = pointer to the destination point
350 * @const ec *p@ = pointer to the operand point
351 *
352 * Returns: The destination point.
353 *
354 * Use: Computes the negation of the given point.
355 */
356
357 ec *ec_neg(ec_curve *c, ec *d, const ec *p)
358 {
359 EC_IN(c, d, p);
360 EC_NEG(c, d, d);
361 return (EC_OUT(c, d, d));
362 }
363
364 /* --- @ec_add@ --- *
365 *
366 * Arguments: @ec_curve *c@ = pointer to an elliptic curve
367 * @ec *d@ = pointer to the destination point
368 * @const ec *p, *q@ = pointers to the operand points
369 *
370 * Returns: ---
371 *
372 * Use: Adds two points on an elliptic curve.
373 */
374
375 ec *ec_add(ec_curve *c, ec *d, const ec *p, const ec *q)
376 {
377 ec pp = EC_INIT, qq = EC_INIT;
378 EC_IN(c, &pp, p);
379 EC_IN(c, &qq, q);
380 EC_ADD(c, d, &pp, &qq);
381 EC_OUT(c, d, d);
382 EC_DESTROY(&pp);
383 EC_DESTROY(&qq);
384 return (d);
385 }
386
387 /* --- @ec_sub@ --- *
388 *
389 * Arguments: @ec_curve *c@ = pointer to an elliptic curve
390 * @ec *d@ = pointer to the destination point
391 * @const ec *p, *q@ = pointers to the operand points
392 *
393 * Returns: The destination @d@.
394 *
395 * Use: Subtracts one point from another on an elliptic curve.
396 */
397
398 ec *ec_sub(ec_curve *c, ec *d, const ec *p, const ec *q)
399 {
400 ec pp = EC_INIT, qq = EC_INIT;
401 EC_IN(c, &pp, p);
402 EC_IN(c, &qq, q);
403 EC_SUB(c, d, &pp, &qq);
404 EC_OUT(c, d, d);
405 EC_DESTROY(&pp);
406 EC_DESTROY(&qq);
407 return (d);
408 }
409
410 /* --- @ec_dbl@ --- *
411 *
412 * Arguments: @ec_curve *c@ = pointer to an elliptic curve
413 * @ec *d@ = pointer to the destination point
414 * @const ec *p@ = pointer to the operand point
415 *
416 * Returns: ---
417 *
418 * Use: Doubles a point on an elliptic curve.
419 */
420
421 ec *ec_dbl(ec_curve *c, ec *d, const ec *p)
422 {
423 EC_IN(c, d, p);
424 EC_DBL(c, d, d);
425 return (EC_OUT(c, d, d));
426 }
427
428 /* --- @ec_check@ --- *
429 *
430 * Arguments: @ec_curve *c@ = pointer to an elliptic curve
431 * @const ec *p@ = pointer to the point
432 *
433 * Returns: Zero if OK, nonzero if this is an invalid point.
434 *
435 * Use: Checks that a point is actually on an elliptic curve.
436 */
437
438 int ec_check(ec_curve *c, const ec *p)
439 {
440 ec t = EC_INIT;
441 int rc;
442
443 if (EC_ATINF(p))
444 return (0);
445 EC_IN(c, &t, p);
446 rc = EC_CHECK(c, &t);
447 EC_DESTROY(&t);
448 return (rc);
449 }
450
451 /* --- @ec_rand@ --- *
452 *
453 * Arguments: @ec_curve *c@ = pointer to an elliptic curve
454 * @ec *d@ = pointer to the destination point
455 * @grand *r@ = random number source
456 *
457 * Returns: The destination @d@.
458 *
459 * Use: Finds a random point on the given curve.
460 */
461
462 ec *ec_rand(ec_curve *c, ec *d, grand *r)
463 {
464 mp *x = MP_NEW;
465 do x = F_RAND(c->f, x, r); while (!EC_FIND(c, d, x));
466 mp_drop(x);
467 if (grand_range(r, 2)) EC_NEG(c, d, d);
468 return (EC_OUT(c, d, d));
469 }
470
471 /*----- That's all, folks -------------------------------------------------*/