3 * $Id: gfshare.c,v 1.3 2000/06/22 18:04:13 mdw Exp $
5 * Secret sharing over %$\gf(2^8)$%
7 * (c) 2000 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
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.
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.
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,
30 /*----- Revision history --------------------------------------------------*
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.
37 * Revision 1.2 2000/06/18 23:12:15 mdw
38 * Change typesetting of Galois Field names.
40 * Revision 1.1 2000/06/17 10:56:30 mdw
41 * Fast but nonstandard secret sharing system.
45 /*----- Header files ------------------------------------------------------*/
52 #include <mLib/alloc.h>
53 #include <mLib/bits.h>
57 #include "gfshare-tab.h"
60 /*----- Static variables --------------------------------------------------*/
62 static octet gflog[] = GFSHARE_LOG, gfexp[] = GFSHARE_EXP;
64 /*----- Main code ---------------------------------------------------------*/
66 /* --- @gfshare_create@ --- *
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
74 * Use: Initializes a sharing context.
77 void gfshare_create(gfshare *s, unsigned t, unsigned n, size_t sz)
87 /* --- @gfshare_destroy@ --- *
89 * Arguments: @gfshare *s@ = pointer to share context to destroy
93 * Use: Disposes of a sharing context. The allocations for the
94 * individual shares and the vector @v@ are freed; the secret is
98 void gfshare_destroy(gfshare *s)
103 /* --- Dispose of the share vector --- */
112 for (i = 0; i < n; i++) {
120 /* --- @gfshare_mkshares@ --- *
122 * Arguments: @gfshare *s@ = pointer to share context to fill in
123 * @grand *r@ = pointer to random number source
127 * Use: Generates @c->n@ secret shares, such that any @c->t@ of them
128 * may be used to recover the secret.
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.
137 void gfshare_mkshares(gfshare *s, grand *r)
142 /* --- Construct the coefficients --- */
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);
149 /* --- Construct the shares --- */
152 s->v = xmalloc(s->n * sizeof(gfshare_pt));
154 for (i = 0; i < s->n; i++) {
157 unsigned ilog = gflog[i + 1];
159 /* --- Evaluate the polynomial at %$x = i + 1$% --- */
161 s->v[i].y = XS_ALLOC(s->sz);
162 memcpy(s->v[i].y, p, s->sz);
164 for (j = 1; j < s->t; j++) {
165 octet *q = s->v[i].y;
167 for (k = 0; k < s->sz; k++) {
170 qq = gfexp[ilog + gflog[qq]];
177 /* --- Dispose of various bits of old rubbish --- */
182 /* --- @gfshare_add@ --- *
184 * Arguments: @gfshare *s@ = pointer to sharing context
185 * @unsigned x@ = which share number this is
186 * @const octet *y@ = the share value
188 * Returns: Number of shares required before recovery may be performed.
190 * Use: Adds a share to the context. The context must have been
191 * initialized with the correct threshold @t@.
194 unsigned gfshare_add(gfshare *s, unsigned x, const octet *y)
196 /* --- If no vector has been allocated, create one --- */
199 s->v = xmalloc(s->t * sizeof(gfshare_pt));
203 assert(((void)"Share context is full", s->i < s->t));
205 /* --- Store the share in the vector --- */
208 s->v[s->i].y = XS_ALLOC(s->sz);
209 memcpy(s->v[s->i].y, y, s->sz);
214 return (s->t - s->i);
217 /* --- @gfshare_combine@ --- *
219 * Arguments: @gfshare *s@ = pointer to share context
220 * @octet *buf@ = pointer to output buffer for the secret
224 * Use: Reconstructs a secret, given enough shares.
227 void gfshare_combine(gfshare *s, octet *buf)
231 /* --- Sanity checking --- */
233 assert(((void)"Not enough shares yet", s->i == s->t));
235 /* --- Grind through the shares --- */
237 memset(buf, 0, s->sz);
239 for (i = 0; i < s->t; i++) {
240 unsigned c = 0, ci = 0;
242 /* --- Compute the magic coefficient --- */
244 for (j = 0; j < s->t; j++) {
247 c += gflog[s->v[j].x + 1];
250 ci += gflog[(s->v[i].x + 1) ^ (s->v[j].x + 1)];
258 /* --- Work out another layer of the secret --- */
260 for (j = 0; j < s->sz; j++) {
262 buf[j] ^= gfexp[c + gflog[s->v[i].y[j]]];
267 /*----- Test rig ----------------------------------------------------------*/
273 static int verify(grand *r)
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;
279 gfshare_pt *v = xmalloc(t * sizeof(gfshare_pt));
280 unsigned *p = xmalloc(n * sizeof(unsigned));
281 octet *sec = xmalloc(len), *sbuf = xmalloc(len);
287 for (i = 0; i < n; i++)
289 for (i = 0; i < t; i++) {
290 unsigned long j = r->ops->range(r, n - i);
296 r->ops->fill(r, sec, len);
298 gfshare_create(&s, t, n, len);
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);
309 gfshare_create(&s, t, n, len);
310 for (i = 0; i < t; i++) {
311 gfshare_add(&s, v[i].x, v[i].y);
313 gfshare_combine(&s, sbuf);
316 if (memcmp(sec, sbuf, len) != 0) {
318 fprintf(stderr, "\nbad recombination of shares\n");
324 for (i = 0; i < t; i++)
334 grand *r = fibrand_create(0);
338 fputs("gfshare: ", stdout);
339 for (i = 0; i < 40; i++) {
347 fputs(" ok\n", stdout);
349 fputs(" failed\n", stdout);
350 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
355 /*----- That's all, folks -------------------------------------------------*/