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