Add cyclic group abstraction, with test code. Separate off exponentation
[u/mdw/catacomb] / f-prime.c
1 /* -*-c-*-
2 *
3 * $Id: f-prime.c,v 1.8 2004/04/01 12:50:09 mdw Exp $
4 *
5 * Prime fields with Montgomery arithmetic
6 *
7 * (c) 2001 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 /*----- Revision history --------------------------------------------------*
31 *
32 * $Log: f-prime.c,v $
33 * Revision 1.8 2004/04/01 12:50:09 mdw
34 * Add cyclic group abstraction, with test code. Separate off exponentation
35 * functions for better static linking. Fix a buttload of bugs on the way.
36 * Generally ensure that negative exponents do inversion correctly. Add
37 * table of standard prime-field subgroups. (Binary field subgroups are
38 * currently unimplemented but easy to add if anyone ever finds a good one.)
39 *
40 * Revision 1.7 2004/03/27 17:54:11 mdw
41 * Standard curves and curve checking.
42 *
43 * Revision 1.6 2004/03/23 15:19:32 mdw
44 * Test elliptic curves more thoroughly.
45 *
46 * Revision 1.5 2004/03/23 12:08:26 mdw
47 * Random field-element selection.
48 *
49 * Revision 1.4 2004/03/21 22:52:06 mdw
50 * Merge and close elliptic curve branch.
51 *
52 * Revision 1.3.4.3 2004/03/21 22:39:46 mdw
53 * Elliptic curves on binary fields work.
54 *
55 * Revision 1.3.4.2 2004/03/20 00:13:31 mdw
56 * Projective coordinates for prime curves
57 *
58 * Revision 1.3.4.1 2003/06/10 13:43:53 mdw
59 * Simple (non-projective) curves over prime fields now seem to work.
60 *
61 * Revision 1.3 2003/05/15 23:25:59 mdw
62 * Make elliptic curve stuff build.
63 *
64 * Revision 1.2 2002/01/13 13:48:44 mdw
65 * Further progress.
66 *
67 * Revision 1.1 2001/04/29 18:12:33 mdw
68 * Prototype version.
69 *
70 */
71
72 /*----- Header files ------------------------------------------------------*/
73
74 #include <mLib/sub.h>
75
76 #include "field.h"
77 #include "mpmont.h"
78 #include "mprand.h"
79
80 /*----- Data structures ---------------------------------------------------*/
81
82 typedef struct fctx {
83 field f;
84 mpmont mm;
85 } fctx;
86
87 /*----- Main code ---------------------------------------------------------*/
88
89 /* --- Field operations --- */
90
91 static void fdestroy(field *ff)
92 {
93 fctx *f = (fctx *)ff;
94 mpmont_destroy(&f->mm);
95 DESTROY(f);
96 }
97
98 static mp *frand(field *ff, mp *d, grand *r)
99 {
100 fctx *f = (fctx *)ff;
101 return (mprand_range(d, f->mm.m, r, 0));
102 }
103
104 static mp *fin(field *ff, mp *d, mp *x)
105 {
106 fctx *f = (fctx *)ff;
107 mp_div(0, &d, x, f->mm.m);
108 return (mpmont_mul(&f->mm, d, d, f->mm.r2));
109 }
110
111 static mp *fout(field *ff, mp *d, mp *x)
112 {
113 fctx *f = (fctx *)ff;
114 return (mpmont_reduce(&f->mm, d, x));
115 }
116
117 static int fzerop(field *ff, mp *x)
118 {
119 return (!MP_LEN(x));
120 }
121
122 static mp *fneg(field *ff, mp *d, mp *x)
123 {
124 fctx *f = (fctx *)ff;
125 return (mp_sub(d, f->mm.m, x));
126 }
127
128 static mp *fadd(field *ff, mp *d, mp *x, mp *y)
129 {
130 fctx *f = (fctx *)ff;
131 d = mp_add(d, x, y);
132 if (d->f & MP_NEG)
133 d = mp_add(d, d, f->mm.m);
134 else if (MP_CMP(d, >, f->mm.m))
135 d = mp_sub(d, d, f->mm.m);
136 return (d);
137 }
138
139 static mp *fsub(field *ff, mp *d, mp *x, mp *y)
140 {
141 fctx *f = (fctx *)ff;
142 d = mp_sub(d, x, y);
143 if (d->f & MP_NEG)
144 d = mp_add(d, d, f->mm.m);
145 else if (MP_CMP(d, >, f->mm.m))
146 d = mp_sub(d, d, f->mm.m);
147 return (d);
148 }
149
150 static mp *fmul(field *ff, mp *d, mp *x, mp *y)
151 {
152 fctx *f = (fctx *)ff;
153 return (mpmont_mul(&f->mm, d, x, y));
154 }
155
156 static mp *fsqr(field *ff, mp *d, mp *x)
157 {
158 fctx *f = (fctx *)ff;
159 d = mp_sqr(d, x);
160 return (mpmont_reduce(&f->mm, d, d));
161 }
162
163 static mp *finv(field *ff, mp *d, mp *x)
164 {
165 fctx *f = (fctx *)ff;
166 d = mpmont_reduce(&f->mm, d, x);
167 mp_gcd(0, 0, &d, f->mm.m, d);
168 return (mpmont_mul(&f->mm, d, d, f->mm.r2));
169 }
170
171 static mp *freduce(field *ff, mp *d, mp *x)
172 {
173 fctx *f = (fctx *)ff;
174 mp_div(0, &d, x, f->mm.m);
175 return (d);
176 }
177
178 static mp *fsqrt(field *ff, mp *d, mp *x)
179 {
180 fctx *f = (fctx *)ff;
181 d = mpmont_reduce(&f->mm, d, x);
182 d = mp_modsqrt(d, d, f->mm.m);
183 if (!d)
184 return (d);
185 return (mpmont_mul(&f->mm, d, d, f->mm.r2));
186 }
187
188 static mp *fdbl(field *ff, mp *d, mp *x)
189 {
190 fctx *f = (fctx *)ff;
191 d = mp_lsl(d, x, 1);
192 if (MP_CMP(d, >, f->mm.m))
193 d = mp_sub(d, d, f->mm.m);
194 return (d);
195 }
196
197 static mp *ftpl(field *ff, mp *d, mp *x)
198 {
199 fctx *f = (fctx *)ff;
200 MP_DEST(d, MP_LEN(x) + 1, x->f);
201 MPX_UMULN(d->v, d->vl, x->v, x->vl, 3);
202 while (MP_CMP(d, >, f->mm.m))
203 d = mp_sub(d, d, f->mm.m);
204 return (d);
205 }
206
207 static mp *fqdl(field *ff, mp *d, mp *x)
208 {
209 fctx *f = (fctx *)ff;
210 d = mp_lsl(d, x, 2);
211 while (MP_CMP(d, >, f->mm.m))
212 d = mp_sub(d, d, f->mm.m);
213 return (d);
214 }
215
216 static mp *fhlv(field *ff, mp *d, mp *x)
217 {
218 fctx *f = (fctx *)ff;
219 if (!MP_LEN(x)) {
220 MP_COPY(x);
221 MP_DROP(d);
222 return (x);
223 }
224 if (x->v[0] & 1) {
225 d = mp_add(d, x, f->mm.m);
226 x = d;
227 }
228 return (mp_lsr(d, x, 1));
229 }
230
231 /* --- Field operations table --- */
232
233 static field_ops fops = {
234 FTY_PRIME, "prime",
235 fdestroy, frand, field_stdsamep,
236 fin, fout,
237 fzerop, fneg, fadd, fsub, fmul, fsqr, finv, freduce, fsqrt,
238 0,
239 fdbl, ftpl, fqdl, fhlv
240 };
241
242 /* --- @field_prime@ --- *
243 *
244 * Arguments: @mp *p@ = the characteristic of the field
245 *
246 * Returns: A pointer to the field.
247 *
248 * Use: Creates a field structure for a prime field of size %$p$%,
249 * using Montgomery reduction for arithmetic.
250 */
251
252 field *field_prime(mp *p)
253 {
254 fctx *f = CREATE(fctx);
255 f->f.ops = &fops;
256 mpmont_create(&f->mm, p);
257 f->f.zero = MP_ZERO;
258 f->f.one = f->mm.r;
259 f->f.m = f->mm.m;
260 f->f.nbits = mp_bits(p);
261 f->f.noctets = (f->f.nbits + 7) >> 3;
262 return (&f->f);
263 }
264
265 /*----- That's all, folks -------------------------------------------------*/