chiark / gitweb /
Improve secret reconstruction -- compute coefficients as needed rather
[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 -------------------------------------------------*/