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