dcf8a101673dbce3e795608655f494a3819d9161
[u/mdw/catacomb] / g-ec.c
1 /* -*-c-*-
2 *
3 * $Id: g-ec.c,v 1.3 2004/04/04 19:04:11 mdw Exp $
4 *
5 * Abstraction for elliptic curve groups
6 *
7 * (c) 2004 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: g-ec.c,v $
33 * Revision 1.3 2004/04/04 19:04:11 mdw
34 * Raw I/O of elliptic curve points and group elements.
35 *
36 * Revision 1.2 2004/04/03 03:32:05 mdw
37 * General robustification.
38 *
39 * Revision 1.1 2004/04/01 12:50:09 mdw
40 * Add cyclic group abstraction, with test code. Separate off exponentation
41 * functions for better static linking. Fix a buttload of bugs on the way.
42 * Generally ensure that negative exponents do inversion correctly. Add
43 * table of standard prime-field subgroups. (Binary field subgroups are
44 * currently unimplemented but easy to add if anyone ever finds a good one.)
45 *
46 */
47
48 /*----- Header files ------------------------------------------------------*/
49
50 #include <ctype.h>
51
52 #include <mLib/sub.h>
53
54 #define ge ec
55 #include "group.h"
56 #include "ec-raw.h"
57
58 /*----- Data structures ---------------------------------------------------*/
59
60 typedef struct gctx {
61 group g;
62 ec id, gen;
63 ec_info ei;
64 } gctx;
65
66 /*----- Main code ---------------------------------------------------------*/
67
68 /* --- Group operations --- */
69
70 static void gdestroygroup(group *gg) {
71 gctx *g = (gctx *)gg;
72 EC_DESTROY(&g->gen);
73 ec_freeinfo(&g->ei);
74 DESTROY(g);
75 }
76
77 static ec *gcreate(group *gg)
78 { ec *x = CREATE(ec); EC_CREATE(x); return (x); }
79
80 static void gcopy(group *gg, ec *d, ec *x) { EC_COPY(d, x); }
81
82 static void gburn(group *gg, ec *x) { if (x->x) (x->x)->f |= MP_BURN; }
83
84 static void gdestroy(group *gg, ec *x) { EC_DESTROY(x); DESTROY(x); }
85
86 static int gsamep(group *gg, group *hh) {
87 gctx *g = (gctx *)gg, *h = (gctx *)hh;
88 return (ec_sameinfop(&g->ei, &h->ei));
89 }
90
91 static int geq(group *gg, ec *x, ec *y) {
92 gctx *g = (gctx *)gg; EC_FIX(g->ei.c, x, x); EC_FIX(g->ei.c, y, y);
93 return (EC_EQ(x, y));
94 }
95
96 static int gidentp(group *gg, ec *x) { return (EC_ATINF(x)); }
97
98 static const char *gcheck(group *gg, grand *gr)
99 { gctx *g = (gctx *)gg; return (ec_checkinfo(&g->ei, gr)); }
100
101 static void gmul(group *gg, ec *d, ec *x, ec *y)
102 { gctx *g = (gctx *)gg; EC_ADD(g->ei.c, d, x, y); }
103
104 static void gsqr(group *gg, ec *d, ec *x)
105 { gctx *g = (gctx *)gg; EC_DBL(g->ei.c, d, x); }
106
107 static void ginv(group *gg, ec *d, ec *x)
108 { gctx *g = (gctx *)gg; EC_NEG(g->ei.c, d, x); }
109
110 static void gdiv(group *gg, ec *d, ec *x, ec *y)
111 { gctx *g = (gctx *)gg; EC_SUB(g->ei.c, d, x, y); }
112
113 static void gexp(group *gg, ec *d, ec *x, mp *n)
114 { gctx *g = (gctx *)gg; ec_imul(g->ei.c, d, x, n); }
115
116 static void gmexp(group *gg, ec *d, const group_expfactor *f, size_t n) {
117 gctx *g = (gctx *)gg; size_t i;
118 ec_mulfactor *ff = xmalloc(n * sizeof(ec_mulfactor));
119 for (i = 0; i < n; i++) { ff[i].base = *f[i].base; ff[i].exp = f[i].exp; }
120 ec_immul(g->ei.c, d, ff, n); xfree(ff);
121 }
122
123 static int gread(group *gg, ec *d, const mptext_ops *ops, void *p) {
124 gctx *g = (gctx *)gg;
125 ec t = EC_INIT;
126 int rc = -1;
127 int ch;
128
129 ch = ops->get(p);
130 if (tolower(ch) == 'i') {
131 if (tolower(ops->get(p)) != 'n' || tolower(ops->get(p)) != 'f')
132 return (-1);
133 EC_SETINF(d);
134 return (0);
135 }
136 ops->unget(ch, p);
137 if ((t.x = mp_read(MP_NEW, 0, ops, p)) == 0) goto done;
138 do ch = ops->get(p); while (ch == ',' || isspace(ch)); ops->unget(ch, p);
139 if ((t.y = mp_read(MP_NEW, 0, ops, p)) == 0) goto done;
140 EC_IN(g->ei.c, &t, &t);
141 if (EC_CHECK(g->ei.c, &t)) goto done;
142 EC_COPY(d, &t); rc = 0;
143 EC_DESTROY(&t);
144 done:
145 return (rc);
146 }
147
148 static int gwrite(group *gg, ec *x, const mptext_ops *ops, void *p) {
149 gctx *g = (gctx *)gg; int rc = -1; ec t = EC_INIT; EC_OUT(g->ei.c, &t, x);
150 if (EC_ATINF(&t)) rc = ops->put("inf", 3, p);
151 else if (!ops->put("0x", 2, p) && !mp_write(t.x, 16, ops, p) &&
152 !ops->put(", 0x", 4, p) && !mp_write(t.y, 16, ops, p)) rc = 0;
153 EC_DESTROY(&t); return (rc);
154 }
155
156 static mp *gtoint(group *gg, mp *d, ec *x) {
157 gctx *g = (gctx *)gg; ec t = EC_INIT; mp *i; if (EC_ATINF(x)) i = 0;
158 else { EC_OUT(g->ei.c, &t, x); i = MP_COPY(t.x); EC_DESTROY(&t); }
159 mp_drop(d); return (i);
160 }
161
162 static int gfromint(group *gg, ec *d, mp *x) {
163 gctx *g = (gctx *)gg; ec t = EC_INIT;
164 if (!ec_find(g->ei.c, &t, x)) return (-1);
165 EC_IN(g->ei.c, d, &t); EC_DESTROY(&t); return (0);
166 }
167
168 static int gtoec(group *gg, ec *d, ec *x)
169 { gctx *g = (gctx *)gg; EC_OUT(g->ei.c, d, x); return (0); }
170
171 static int gfromec(group *gg, ec *d, ec *x) {
172 gctx *g = (gctx *)gg; ec t = EC_INIT; int rc; EC_IN(g->ei.c, &t, x);
173 rc = EC_CHECK(g->ei.c, &t); if (!rc) EC_COPY(d, &t); EC_DESTROY(&t);
174 return (rc);
175 }
176
177 static int gtobuf(group *gg, buf *b, ec *x) {
178 gctx *g = (gctx *)gg; ec t = EC_INIT; int rc;
179 EC_OUT(g->ei.c, &t, x); rc = buf_putec(b, &t); EC_DESTROY(&t); return (rc);
180 }
181
182 static int gfrombuf(group *gg, buf *b, ec *d) {
183 gctx *g = (gctx *)gg; ec t = EC_INIT; int rc;
184 if (buf_getec(b, &t)) return (-1);
185 EC_IN(g->ei.c, &t, &t); rc = EC_CHECK(g->ei.c, &t);
186 if (!rc) EC_COPY(d, &t); EC_DESTROY(&t); return (rc);
187 }
188
189 static int gtoraw(group *gg, buf *b, ec *x) {
190 gctx *g = (gctx *)gg; ec t = EC_INIT; int rc;
191 EC_OUT(g->ei.c, &t, x); rc = ec_putraw(g->ei.c, b, &t);
192 EC_DESTROY(&t); return (rc);
193 }
194
195 static int gfromraw(group *gg, buf *b, ec *d) {
196 gctx *g = (gctx *)gg; ec t = EC_INIT; int rc;
197 if (ec_getraw(g->ei.c, b, &t)) return (-1);
198 EC_IN(g->ei.c, &t, &t); rc = EC_CHECK(g->ei.c, &t);
199 if (!rc) EC_COPY(d, &t); EC_DESTROY(&t); return (rc);
200 }
201
202 /* --- @group_ec@ --- *
203 *
204 * Arguments: @const ec_info *ei@ = elliptic curve parameters
205 *
206 * Returns: A pointer to the group.
207 *
208 * Use: Constructs an abstract group interface for an elliptic curve
209 * group. Group elements are @ec@ structures. The contents of
210 * the @ec_info@ structure becomes the property of the @group@
211 * object; you can (and should) free the structure itself, but
212 * calling @ec_freeinfo@ on it is not allowed.
213 */
214
215 static const group_ops gops = {
216 GTY_EC,
217 gdestroygroup, gcreate, gcopy, gburn, gdestroy,
218 gsamep, geq, gidentp,
219 gcheck,
220 gmul, gsqr, ginv, gdiv, gexp, gmexp,
221 gread, gwrite,
222 gtoint, gfromint, gtoec, gfromec, gtobuf, gfrombuf, gtoraw, gfromraw
223 };
224
225 group *group_ec(const ec_info *ei)
226 {
227 gctx *g = CREATE(gctx);
228
229 g->g.ops = &gops;
230 g->g.nbits = ei->c->f->nbits * 2;
231 g->g.noctets = ei->c->f->noctets * 2 + 1;
232 g->ei = *ei;
233 EC_CREATE(&g->id);
234 g->g.i = &g->id;
235 EC_CREATE(&g->gen);
236 g->g.g = &g->gen;
237 EC_IN(g->ei.c, &g->gen, &ei->g);
238 g->g.r = ei->r;
239 g->g.h = ei->h;
240 return (&g->g);
241 }
242
243 /*----- That's all, folks -------------------------------------------------*/