math/mpreduce.h: Missing include files.
[u/mdw/catacomb] / misc / gfshare.c
CommitLineData
6c1035f5 1/* -*-c-*-
2 *
eaa515d8 3 * Secret sharing over %$\gf{2^8}$%
6c1035f5 4 *
5 * (c) 2000 Straylight/Edgeware
6 */
7
45c0fd36 8/*----- Licensing notice --------------------------------------------------*
6c1035f5 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.
45c0fd36 16 *
6c1035f5 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.
45c0fd36 21 *
6c1035f5 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
6c1035f5 28/*----- Header files ------------------------------------------------------*/
29
30#include <assert.h>
31#include <stdarg.h>
32#include <stdio.h>
cb06abce 33#include <string.h>
6c1035f5 34
35#include <mLib/alloc.h>
36#include <mLib/bits.h>
37
38#include "arena.h"
39#include "gfshare.h"
6c1035f5 40#include "grand.h"
41
42/*----- Static variables --------------------------------------------------*/
43
e5b61a8d 44extern const octet gfshare_log[256], gfshare_exp[510];
6c1035f5 45
46/*----- Main code ---------------------------------------------------------*/
47
48/* --- @gfshare_create@ --- *
49 *
50 * Arguments: @gfshare *s@ = pointer to share context to initialize
3d64a35c 51 * @unsigned t@ = threshold for the system
6c1035f5 52 * @size_t sz@ = size of the secret
53 *
54 * Returns: ---
55 *
56 * Use: Initializes a sharing context.
57 */
58
3d64a35c 59void gfshare_create(gfshare *s, unsigned t, size_t sz)
6c1035f5 60{
61 s->t = t;
6c1035f5 62 s->i = 0;
63 s->sz = sz;
6c1035f5 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
78void gfshare_destroy(gfshare *s)
79{
3d64a35c 80 if (s->v)
81 XS_FREE(s->v);
6c1035f5 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
5d4fee2a 88 * @const void *buf@ = pointer to the secret to share
6c1035f5 89 *
90 * Returns: ---
91 *
3d64a35c 92 * Use: Initializes a sharing context to be able to create shares.
6c1035f5 93 * The context structure is expected to be mostly filled in. In
5d4fee2a 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.
6c1035f5 98 */
99
5d4fee2a 100void gfshare_mkshares(gfshare *s, grand *r, const void *buf)
6c1035f5 101{
3d64a35c 102 s->v = XS_ALLOC(s->sz * s->t);
103 r->ops->fill(r, s->v, s->sz * (s->t - 1));
5d4fee2a 104 memcpy(s->v + s->sz * (s->t - 1), buf, s->sz);
3d64a35c 105}
6c1035f5 106
3d64a35c 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 *
ea303d6c 113 * Returns: ---
3d64a35c 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 */
6c1035f5 118
3d64a35c 119void gfshare_get(gfshare *s, unsigned x, void *buf)
120{
121 unsigned i;
122 const octet *p = s->v;
e5b61a8d 123 unsigned ilog = gfshare_log[x + 1];
3d64a35c 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)
e5b61a8d 136 qq = gfshare_exp[ilog + gfshare_log[qq]];
3d64a35c 137 *q++ = qq ^ *p++;
6c1035f5 138 }
6c1035f5 139 }
6c1035f5 140}
141
aec42286 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
151int 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
6c1035f5 162/* --- @gfshare_add@ --- *
163 *
164 * Arguments: @gfshare *s@ = pointer to sharing context
165 * @unsigned x@ = which share number this is
3d64a35c 166 * @const void *y@ = the share value
6c1035f5 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
3d64a35c 174unsigned gfshare_add(gfshare *s, unsigned x, const void *y)
6c1035f5 175{
3d64a35c 176 octet *p;
177
aec42286 178 assert(((void)"Share context is full", s->i < s->t));
179 assert(((void)"Share already present", !gfshare_addedp(s, x)));
180
6c1035f5 181 /* --- If no vector has been allocated, create one --- */
182
183 if (!s->v) {
3d64a35c 184 s->v = XS_ALLOC(s->t * (s->sz + 1));
6c1035f5 185 s->i = 0;
186 }
187
6c1035f5 188 /* --- Store the share in the vector --- */
189
aec42286 190 p = &GFSHARE_INDEX(s, s->i);
3d64a35c 191 *p++ = x + 1;
192 memcpy(p, y, s->sz);
6c1035f5 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
3d64a35c 203 * @void *buf@ = pointer to output buffer for the secret
6c1035f5 204 *
205 * Returns: ---
206 *
207 * Use: Reconstructs a secret, given enough shares.
208 */
209
3d64a35c 210void gfshare_combine(gfshare *s, void *buf)
6c1035f5 211{
212 unsigned i, j;
3d64a35c 213 unsigned xi, xj;
6c1035f5 214
215 /* --- Sanity checking --- */
216
217 assert(((void)"Not enough shares yet", s->i == s->t));
218
cb06abce 219 /* --- Grind through the shares --- */
6c1035f5 220
cb06abce 221 memset(buf, 0, s->sz);
6c1035f5 222
223 for (i = 0; i < s->t; i++) {
3d64a35c 224 octet *p = buf;
aec42286 225 octet *q = &GFSHARE_INDEX(s, i);
6c1035f5 226 unsigned c = 0, ci = 0;
cb06abce 227
228 /* --- Compute the magic coefficient --- */
229
3d64a35c 230 xi = *q++;
6c1035f5 231 for (j = 0; j < s->t; j++) {
232 if (i == j)
233 continue;
aec42286 234 xj = GFSHARE_INDEX(s, j);
e5b61a8d 235 c += gfshare_log[xj];
6c1035f5 236 if (c >= 0xff)
237 c -= 0xff;
e5b61a8d 238 ci += gfshare_log[xi ^ xj];
6c1035f5 239 if (ci >= 0xff)
240 ci -= 0xff;
241 }
242 if (ci > c)
243 c += 0xff;
244 c -= ci;
6c1035f5 245
cb06abce 246 /* --- Work out another layer of the secret --- */
6c1035f5 247
3d64a35c 248 p = buf;
cb06abce 249 for (j = 0; j < s->sz; j++) {
3d64a35c 250 if (*q)
e5b61a8d 251 *p ^= gfshare_exp[c + gfshare_log[*q]];
3d64a35c 252 p++, q++;
6c1035f5 253 }
6c1035f5 254 }
6c1035f5 255}
256
257/*----- Test rig ----------------------------------------------------------*/
258
259#ifdef TEST_RIG
260
261#include "fibrand.h"
262
263static 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
3d64a35c 269 octet *v = xmalloc(t * len);
6c1035f5 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
3d64a35c 288 gfshare_create(&s, t, len);
6c1035f5 289
5d4fee2a 290 gfshare_mkshares(&s, r, sec);
3d64a35c 291 for (i = 0; i < t; i++)
292 gfshare_get(&s, p[i], v + (i * len));
6c1035f5 293 gfshare_destroy(&s);
294
3d64a35c 295 gfshare_create(&s, t, len);
296 for (i = 0; i < t; i++)
297 gfshare_add(&s, p[i], v + (i * len));
6c1035f5 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
6c1035f5 309 xfree(v);
310 xfree(p);
311
312 return (ok);
313}
314
315int 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 -------------------------------------------------*/