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