Use the new @mp_odd@ function.
[u/mdw/catacomb] / gfshare.c
1 /* -*-c-*-
2 *
3 * $Id: gfshare.c,v 1.3 2000/06/22 18:04:13 mdw Exp $
4 *
5 * Secret sharing over %$\gf(2^8)$%
6 *
7 * (c) 2000 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: gfshare.c,v $
33 * Revision 1.3 2000/06/22 18:04:13 mdw
34 * Improve secret reconstruction -- compute coefficients as needed rather
35 * than making a big array of them.
36 *
37 * Revision 1.2 2000/06/18 23:12:15 mdw
38 * Change typesetting of Galois Field names.
39 *
40 * Revision 1.1 2000/06/17 10:56:30 mdw
41 * Fast but nonstandard secret sharing system.
42 *
43 */
44
45 /*----- Header files ------------------------------------------------------*/
46
47 #include <assert.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <string.h>
51
52 #include <mLib/alloc.h>
53 #include <mLib/bits.h>
54
55 #include "arena.h"
56 #include "gfshare.h"
57 #include "gfshare-tab.h"
58 #include "grand.h"
59
60 /*----- Static variables --------------------------------------------------*/
61
62 static octet gflog[] = GFSHARE_LOG, gfexp[] = GFSHARE_EXP;
63
64 /*----- Main code ---------------------------------------------------------*/
65
66 /* --- @gfshare_create@ --- *
67 *
68 * Arguments: @gfshare *s@ = pointer to share context to initialize
69 * @unsigned t, n@ = threshold parameters for the system
70 * @size_t sz@ = size of the secret
71 *
72 * Returns: ---
73 *
74 * Use: Initializes a sharing context.
75 */
76
77 void gfshare_create(gfshare *s, unsigned t, unsigned n, size_t sz)
78 {
79 s->t = t;
80 s->n = n;
81 s->i = 0;
82 s->sz = sz;
83 s->s = 0;
84 s->v = 0;
85 }
86
87 /* --- @gfshare_destroy@ --- *
88 *
89 * Arguments: @gfshare *s@ = pointer to share context to destroy
90 *
91 * Returns: ---
92 *
93 * Use: Disposes of a sharing context. The allocations for the
94 * individual shares and the vector @v@ are freed; the secret is
95 * left alone.
96 */
97
98 void gfshare_destroy(gfshare *s)
99 {
100 unsigned n;
101 unsigned i;
102
103 /* --- Dispose of the share vector --- */
104
105 if (s->v) {
106 if (s->i)
107 n = s->i;
108 else if (s->n)
109 n = s->n;
110 else
111 n = s->t;
112 for (i = 0; i < n; i++) {
113 if (s->v[i].y)
114 XS_FREE(s->v[i].y);
115 }
116 xfree(s->v);
117 }
118 }
119
120 /* --- @gfshare_mkshares@ --- *
121 *
122 * Arguments: @gfshare *s@ = pointer to share context to fill in
123 * @grand *r@ = pointer to random number source
124 *
125 * Returns: ---
126 *
127 * Use: Generates @c->n@ secret shares, such that any @c->t@ of them
128 * may be used to recover the secret.
129 *
130 * The context structure is expected to be mostly filled in. In
131 * particular, @t@, @n@, @ssz@ and @s@ must be initialized. If
132 * @v@ is zero, a vector of appropriate size is allocated. You
133 * should use the macro @GFSHARE_INIT@ or @gfshare_create@ to
134 * construct sharing contexts.
135 */
136
137 void gfshare_mkshares(gfshare *s, grand *r)
138 {
139 octet *v;
140 unsigned i;
141
142 /* --- Construct the coefficients --- */
143
144 v = XS_ALLOC(s->sz * s->t);
145 r->ops->fill(r, v, s->sz * (s->t - 1));
146 memcpy(v + s->sz * (s->t - 1), s->s, s->sz);
147
148
149 /* --- Construct the shares --- */
150
151 if (!s->v)
152 s->v = xmalloc(s->n * sizeof(gfshare_pt));
153
154 for (i = 0; i < s->n; i++) {
155 unsigned j;
156 const octet *p = v;
157 unsigned ilog = gflog[i + 1];
158
159 /* --- Evaluate the polynomial at %$x = i + 1$% --- */
160
161 s->v[i].y = XS_ALLOC(s->sz);
162 memcpy(s->v[i].y, p, s->sz);
163 p += s->sz;
164 for (j = 1; j < s->t; j++) {
165 octet *q = s->v[i].y;
166 unsigned k;
167 for (k = 0; k < s->sz; k++) {
168 unsigned qq = *q;
169 if (qq)
170 qq = gfexp[ilog + gflog[qq]];
171 *q++ = qq ^ *p++;
172 }
173 }
174 s->v[i].x = i;
175 }
176
177 /* --- Dispose of various bits of old rubbish --- */
178
179 XS_FREE(v);
180 }
181
182 /* --- @gfshare_add@ --- *
183 *
184 * Arguments: @gfshare *s@ = pointer to sharing context
185 * @unsigned x@ = which share number this is
186 * @const octet *y@ = the share value
187 *
188 * Returns: Number of shares required before recovery may be performed.
189 *
190 * Use: Adds a share to the context. The context must have been
191 * initialized with the correct threshold @t@.
192 */
193
194 unsigned gfshare_add(gfshare *s, unsigned x, const octet *y)
195 {
196 /* --- If no vector has been allocated, create one --- */
197
198 if (!s->v) {
199 s->v = xmalloc(s->t * sizeof(gfshare_pt));
200 s->i = 0;
201 }
202
203 assert(((void)"Share context is full", s->i < s->t));
204
205 /* --- Store the share in the vector --- */
206
207 s->v[s->i].x = x;
208 s->v[s->i].y = XS_ALLOC(s->sz);
209 memcpy(s->v[s->i].y, y, s->sz);
210 s->i++;
211
212 /* --- Done --- */
213
214 return (s->t - s->i);
215 }
216
217 /* --- @gfshare_combine@ --- *
218 *
219 * Arguments: @gfshare *s@ = pointer to share context
220 * @octet *buf@ = pointer to output buffer for the secret
221 *
222 * Returns: ---
223 *
224 * Use: Reconstructs a secret, given enough shares.
225 */
226
227 void gfshare_combine(gfshare *s, octet *buf)
228 {
229 unsigned i, j;
230
231 /* --- Sanity checking --- */
232
233 assert(((void)"Not enough shares yet", s->i == s->t));
234
235 /* --- Grind through the shares --- */
236
237 memset(buf, 0, s->sz);
238
239 for (i = 0; i < s->t; i++) {
240 unsigned c = 0, ci = 0;
241
242 /* --- Compute the magic coefficient --- */
243
244 for (j = 0; j < s->t; j++) {
245 if (i == j)
246 continue;
247 c += gflog[s->v[j].x + 1];
248 if (c >= 0xff)
249 c -= 0xff;
250 ci += gflog[(s->v[i].x + 1) ^ (s->v[j].x + 1)];
251 if (ci >= 0xff)
252 ci -= 0xff;
253 }
254 if (ci > c)
255 c += 0xff;
256 c -= ci;
257
258 /* --- Work out another layer of the secret --- */
259
260 for (j = 0; j < s->sz; j++) {
261 if (s->v[i].y[j])
262 buf[j] ^= gfexp[c + gflog[s->v[i].y[j]]];
263 }
264 }
265 }
266
267 /*----- Test rig ----------------------------------------------------------*/
268
269 #ifdef TEST_RIG
270
271 #include "fibrand.h"
272
273 static int verify(grand *r)
274 {
275 unsigned n = r->ops->range(r, 16) + 8;
276 unsigned t = r->ops->range(r, n - 1) + 1;
277 unsigned len = r->ops->range(r, 32) + 1;
278
279 gfshare_pt *v = xmalloc(t * sizeof(gfshare_pt));
280 unsigned *p = xmalloc(n * sizeof(unsigned));
281 octet *sec = xmalloc(len), *sbuf = xmalloc(len);
282 gfshare s;
283 unsigned i;
284
285 int ok = 1;
286
287 for (i = 0; i < n; i++)
288 p[i] = i;
289 for (i = 0; i < t; i++) {
290 unsigned long j = r->ops->range(r, n - i);
291 unsigned x = p[i];
292 p[i] = p[i + j];
293 p[i + j] = x;
294 }
295
296 r->ops->fill(r, sec, len);
297
298 gfshare_create(&s, t, n, len);
299 s.s = sec;
300
301 gfshare_mkshares(&s, r);
302 for (i = 0; i < t; i++) {
303 v[i].x = s.v[p[i]].x;
304 v[i].y = xmalloc(len);
305 memcpy(v[i].y, s.v[p[i]].y, len);
306 }
307 gfshare_destroy(&s);
308
309 gfshare_create(&s, t, n, len);
310 for (i = 0; i < t; i++) {
311 gfshare_add(&s, v[i].x, v[i].y);
312 }
313 gfshare_combine(&s, sbuf);
314 gfshare_destroy(&s);
315
316 if (memcmp(sec, sbuf, len) != 0) {
317 ok = 0;
318 fprintf(stderr, "\nbad recombination of shares\n");
319 };
320
321 xfree(sec);
322 xfree(sbuf);
323
324 for (i = 0; i < t; i++)
325 xfree(v[i].y);
326 xfree(v);
327 xfree(p);
328
329 return (ok);
330 }
331
332 int main(void)
333 {
334 grand *r = fibrand_create(0);
335 unsigned i;
336 int ok = 1;
337
338 fputs("gfshare: ", stdout);
339 for (i = 0; i < 40; i++) {
340 if (!verify(r))
341 ok = 0;
342 fputc('.', stdout);
343 fflush(stdout);
344 }
345
346 if (ok)
347 fputs(" ok\n", stdout);
348 else
349 fputs(" failed\n", stdout);
350 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
351 }
352
353 #endif
354
355 /*----- That's all, folks -------------------------------------------------*/