1b6c16e36092d88c31295ec69648482ea85d4d53
[catacomb] / math / g-ec.c
1 /* -*-c-*-
2 *
3 * Abstraction for elliptic curve groups
4 *
5 * (c) 2004 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <ctype.h>
31
32 #include <mLib/sub.h>
33
34 #define ge ec
35 #include "ec-raw.h"
36 #include "group-guts.h"
37
38 /*----- Main code ---------------------------------------------------------*/
39
40 /* --- Group operations --- */
41
42 static void gdestroygroup(group *gg) {
43 gctx_ec *g = (gctx_ec *)gg;
44 EC_DESTROY(&g->gen);
45 ec_freeinfo(&g->ei);
46 DESTROY(g);
47 }
48
49 static ec *gcreate(group *gg)
50 { ec *x = CREATE(ec); EC_CREATE(x); return (x); }
51
52 static void gcopy(group *gg, ec *d, ec *x) { EC_COPY(d, x); }
53
54 static void gburn(group *gg, ec *x) { if (x->x) (x->x)->f |= MP_BURN; }
55
56 static void gdestroy(group *gg, ec *x) { EC_DESTROY(x); DESTROY(x); }
57
58 static int gsamep(group *gg, group *hh) {
59 gctx_ec *g = (gctx_ec *)gg, *h = (gctx_ec *)hh;
60 return (ec_sameinfop(&g->ei, &h->ei));
61 }
62
63 static int geq(group *gg, ec *x, ec *y) {
64 gctx_ec *g = (gctx_ec *)gg; EC_FIX(g->ei.c, x, x); EC_FIX(g->ei.c, y, y);
65 return (EC_EQ(x, y));
66 }
67
68 static int gidentp(group *gg, ec *x) { return (EC_ATINF(x)); }
69
70 static const char *gcheck(group *gg, grand *gr)
71 { gctx_ec *g = (gctx_ec *)gg; return (ec_checkinfo(&g->ei, gr)); }
72
73 static void gmul(group *gg, ec *d, ec *x, ec *y)
74 { gctx_ec *g = (gctx_ec *)gg; EC_ADD(g->ei.c, d, x, y); }
75
76 static void gsqr(group *gg, ec *d, ec *x)
77 { gctx_ec *g = (gctx_ec *)gg; EC_DBL(g->ei.c, d, x); }
78
79 static void ginv(group *gg, ec *d, ec *x)
80 { gctx_ec *g = (gctx_ec *)gg; EC_NEG(g->ei.c, d, x); }
81
82 static void gdiv(group *gg, ec *d, ec *x, ec *y)
83 { gctx_ec *g = (gctx_ec *)gg; EC_SUB(g->ei.c, d, x, y); }
84
85 static void gexp(group *gg, ec *d, ec *x, mp *n)
86 { gctx_ec *g = (gctx_ec *)gg; ec_imul(g->ei.c, d, x, n); }
87
88 static void gmexp(group *gg, ec *d, const group_expfactor *f, size_t n) {
89 gctx_ec *g = (gctx_ec *)gg; size_t i;
90 ec_mulfactor *ff = xmalloc(n * sizeof(ec_mulfactor));
91 for (i = 0; i < n; i++) { ff[i].base = *f[i].base; ff[i].exp = f[i].exp; }
92 ec_immul(g->ei.c, d, ff, n); xfree(ff);
93 }
94
95 static int gread(group *gg, ec *d, const mptext_ops *ops, void *p) {
96 gctx_ec *g = (gctx_ec *)gg;
97 ec t = EC_INIT;
98 int rc = -1;
99 int ch;
100
101 ch = ops->get(p);
102 if (tolower(ch) == 'i') {
103 if (tolower(ops->get(p)) != 'n' || tolower(ops->get(p)) != 'f')
104 return (-1);
105 EC_SETINF(d);
106 return (0);
107 }
108 ops->unget(ch, p);
109 if ((t.x = mp_read(MP_NEW, 0, ops, p)) == 0) goto done;
110 do ch = ops->get(p); while (ch == ',' || isspace(ch)); ops->unget(ch, p);
111 if ((t.y = mp_read(MP_NEW, 0, ops, p)) == 0) goto done;
112 EC_IN(g->ei.c, &t, &t);
113 if (EC_CHECK(g->ei.c, &t)) goto done;
114 EC_COPY(d, &t); rc = 0;
115 EC_DESTROY(&t);
116 done:
117 return (rc);
118 }
119
120 static int gwrite(group *gg, ec *x, const mptext_ops *ops, void *p) {
121 gctx_ec *g = (gctx_ec *)gg; int rc = -1; ec t = EC_INIT;
122 EC_OUT(g->ei.c, &t, x); if (EC_ATINF(&t)) rc = ops->put("inf", 3, p);
123 else if (!ops->put("0x", 2, p) && !mp_write(t.x, 16, ops, p) &&
124 !ops->put(", 0x", 4, p) && !mp_write(t.y, 16, ops, p)) rc = 0;
125 EC_DESTROY(&t); return (rc);
126 }
127
128 static mp *gtoint(group *gg, mp *d, ec *x) {
129 gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; mp *i; if (EC_ATINF(x)) i = 0;
130 else { EC_OUT(g->ei.c, &t, x); i = MP_COPY(t.x); EC_DESTROY(&t); }
131 mp_drop(d); return (i);
132 }
133
134 static int gfromint(group *gg, ec *d, mp *x) {
135 gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT;
136 if (!ec_find(g->ei.c, &t, x)) return (-1);
137 EC_IN(g->ei.c, d, &t); EC_DESTROY(&t); return (0);
138 }
139
140 static int gtoec(group *gg, ec *d, ec *x)
141 { gctx_ec *g = (gctx_ec *)gg; EC_OUT(g->ei.c, d, x); return (0); }
142
143 static int gfromec(group *gg, ec *d, const ec *x) {
144 gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; int rc; EC_IN(g->ei.c, &t, x);
145 rc = EC_CHECK(g->ei.c, &t); if (!rc) EC_COPY(d, &t); EC_DESTROY(&t);
146 return (rc);
147 }
148
149 static int gtobuf(group *gg, buf *b, ec *x) {
150 gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; int rc;
151 EC_OUT(g->ei.c, &t, x); rc = buf_putec(b, &t); EC_DESTROY(&t); return (rc);
152 }
153
154 static int gfrombuf(group *gg, buf *b, ec *d) {
155 gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; int rc;
156 if (buf_getec(b, &t)) return (-1);
157 EC_IN(g->ei.c, &t, &t); rc = EC_CHECK(g->ei.c, &t);
158 if (!rc) EC_COPY(d, &t); EC_DESTROY(&t); return (rc);
159 }
160
161 static int gtoraw(group *gg, buf *b, ec *x) {
162 gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; int rc;
163 EC_OUT(g->ei.c, &t, x); rc = ec_putraw(g->ei.c, b, &t);
164 EC_DESTROY(&t); return (rc);
165 }
166
167 static int gfromraw(group *gg, buf *b, ec *d) {
168 gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; int rc;
169 if (ec_getraw(g->ei.c, b, &t)) return (-1);
170 EC_IN(g->ei.c, &t, &t); rc = EC_CHECK(g->ei.c, &t);
171 if (!rc) EC_COPY(d, &t); EC_DESTROY(&t); return (rc);
172 }
173
174 /* --- @group_ec@ --- *
175 *
176 * Arguments: @const ec_info *ei@ = elliptic curve parameters
177 *
178 * Returns: A pointer to the group.
179 *
180 * Use: Constructs an abstract group interface for an elliptic curve
181 * group. Group elements are @ec@ structures. The contents of
182 * the @ec_info@ structure becomes the property of the @group@
183 * object; you can (and should) free the structure itself, but
184 * calling @ec_freeinfo@ on it is not allowed.
185 */
186
187 static const group_ops gops = {
188 GTY_EC, "ec",
189 gdestroygroup, gcreate, gcopy, gburn, gdestroy,
190 gsamep, geq, gidentp,
191 gcheck,
192 gmul, gsqr, ginv, gdiv, gexp, gmexp,
193 gread, gwrite,
194 gtoint, gfromint, gtoec, gfromec, gtobuf, gfrombuf, gtoraw, gfromraw
195 };
196
197 group *group_ec(const ec_info *ei)
198 {
199 gctx_ec *g = CREATE(gctx_ec);
200
201 g->g.ops = &gops;
202 g->g.nbits = ei->c->f->nbits * 2;
203 g->g.noctets = ei->c->f->noctets * 2 + 1;
204 g->ei = *ei;
205 EC_CREATE(&g->id);
206 g->g.i = &g->id;
207 EC_CREATE(&g->gen);
208 g->g.g = &g->gen;
209 EC_IN(g->ei.c, &g->gen, &ei->g);
210 g->g.r = ei->r;
211 g->g.h = ei->h;
212 return (&g->g);
213 }
214
215 /*----- That's all, folks -------------------------------------------------*/