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