chiark / gitweb /
Merge branch 'fixes'
[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 -------------------------------------------------*/