Rearrange build order to ensure that `mptypes.h' exists by the time it's
[u/mdw/catacomb] / gfshare.c
CommitLineData
6c1035f5 1/* -*-c-*-
2 *
4d47e157 3 * $Id: gfshare.c,v 1.2 2000/06/18 23:12:15 mdw Exp $
6c1035f5 4 *
4d47e157 5 * Secret sharing over %$\gf(2^8)$%
6c1035f5 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 $
4d47e157 33 * Revision 1.2 2000/06/18 23:12:15 mdw
34 * Change typesetting of Galois Field names.
35 *
6c1035f5 36 * Revision 1.1 2000/06/17 10:56:30 mdw
37 * Fast but nonstandard secret sharing system.
38 *
39 */
40
41/*----- Header files ------------------------------------------------------*/
42
43#include <assert.h>
44#include <stdarg.h>
45#include <stdio.h>
46
47#include <mLib/alloc.h>
48#include <mLib/bits.h>
49
50#include "arena.h"
51#include "gfshare.h"
52#include "gfshare-tab.h"
53#include "grand.h"
54
55/*----- Static variables --------------------------------------------------*/
56
57static octet gflog[] = GFSHARE_LOG, gfexp[] = GFSHARE_EXP;
58
59/*----- Main code ---------------------------------------------------------*/
60
61/* --- @gfshare_create@ --- *
62 *
63 * Arguments: @gfshare *s@ = pointer to share context to initialize
64 * @unsigned t, n@ = threshold parameters for the system
65 * @size_t sz@ = size of the secret
66 *
67 * Returns: ---
68 *
69 * Use: Initializes a sharing context.
70 */
71
72void gfshare_create(gfshare *s, unsigned t, unsigned n, size_t sz)
73{
74 s->t = t;
75 s->n = n;
76 s->i = 0;
77 s->sz = sz;
78 s->s = 0;
79 s->v = 0;
80}
81
82/* --- @gfshare_destroy@ --- *
83 *
84 * Arguments: @gfshare *s@ = pointer to share context to destroy
85 *
86 * Returns: ---
87 *
88 * Use: Disposes of a sharing context. The allocations for the
89 * individual shares and the vector @v@ are freed; the secret is
90 * left alone.
91 */
92
93void gfshare_destroy(gfshare *s)
94{
95 unsigned n;
96 unsigned i;
97
98 /* --- Dispose of the share vector --- */
99
100 if (s->v) {
101 if (s->i)
102 n = s->i;
103 else if (s->n)
104 n = s->n;
105 else
106 n = s->t;
107 for (i = 0; i < n; i++) {
108 if (s->v[i].y)
109 XS_FREE(s->v[i].y);
110 }
111 xfree(s->v);
112 }
113}
114
115/* --- @gfshare_mkshares@ --- *
116 *
117 * Arguments: @gfshare *s@ = pointer to share context to fill in
118 * @grand *r@ = pointer to random number source
119 *
120 * Returns: ---
121 *
122 * Use: Generates @c->n@ secret shares, such that any @c->t@ of them
123 * may be used to recover the secret.
124 *
125 * The context structure is expected to be mostly filled in. In
126 * particular, @t@, @n@, @ssz@ and @s@ must be initialized. If
127 * @v@ is zero, a vector of appropriate size is allocated. You
128 * should use the macro @GFSHARE_INIT@ or @gfshare_create@ to
129 * construct sharing contexts.
130 */
131
132void gfshare_mkshares(gfshare *s, grand *r)
133{
134 octet *v;
135 unsigned i;
136
137 /* --- Construct the coefficients --- */
138
139 v = XS_ALLOC(s->sz * s->t);
140 r->ops->fill(r, v, s->sz * (s->t - 1));
141 memcpy(v + s->sz * (s->t - 1), s->s, s->sz);
142
143
144 /* --- Construct the shares --- */
145
146 if (!s->v)
147 s->v = xmalloc(s->n * sizeof(gfshare_pt));
148
149 for (i = 0; i < s->n; i++) {
150 unsigned j;
151 const octet *p = v;
152 unsigned ilog = gflog[i + 1];
153
154 /* --- Evaluate the polynomial at %$x = i + 1$% --- */
155
156 s->v[i].y = XS_ALLOC(s->sz);
157 memcpy(s->v[i].y, p, s->sz);
158 p += s->sz;
159 for (j = 1; j < s->t; j++) {
160 octet *q = s->v[i].y;
161 unsigned k;
162 for (k = 0; k < s->sz; k++) {
163 unsigned qq = *q;
164 if (qq)
165 qq = gfexp[ilog + gflog[qq]];
166 *q++ = qq ^ *p++;
167 }
168 }
169 s->v[i].x = i;
170 }
171
172 /* --- Dispose of various bits of old rubbish --- */
173
174 XS_FREE(v);
175}
176
177/* --- @gfshare_add@ --- *
178 *
179 * Arguments: @gfshare *s@ = pointer to sharing context
180 * @unsigned x@ = which share number this is
181 * @const octet *y@ = the share value
182 *
183 * Returns: Number of shares required before recovery may be performed.
184 *
185 * Use: Adds a share to the context. The context must have been
186 * initialized with the correct threshold @t@.
187 */
188
189unsigned gfshare_add(gfshare *s, unsigned x, const octet *y)
190{
191 /* --- If no vector has been allocated, create one --- */
192
193 if (!s->v) {
194 s->v = xmalloc(s->t * sizeof(gfshare_pt));
195 s->i = 0;
196 }
197
198 assert(((void)"Share context is full", s->i < s->t));
199
200 /* --- Store the share in the vector --- */
201
202 s->v[s->i].x = x;
203 s->v[s->i].y = XS_ALLOC(s->sz);
204 memcpy(s->v[s->i].y, y, s->sz);
205 s->i++;
206
207 /* --- Done --- */
208
209 return (s->t - s->i);
210}
211
212/* --- @gfshare_combine@ --- *
213 *
214 * Arguments: @gfshare *s@ = pointer to share context
215 * @octet *buf@ = pointer to output buffer for the secret
216 *
217 * Returns: ---
218 *
219 * Use: Reconstructs a secret, given enough shares.
220 */
221
222void gfshare_combine(gfshare *s, octet *buf)
223{
224 unsigned i, j;
225 octet *v;
226
227 /* --- Sanity checking --- */
228
229 assert(((void)"Not enough shares yet", s->i == s->t));
230
231 /* --- Precomputation of coefficients --- */
232
233 v = XS_ALLOC(s->t);
234
235 for (i = 0; i < s->t; i++) {
236 unsigned c = 0, ci = 0;
237 for (j = 0; j < s->t; j++) {
238 if (i == j)
239 continue;
240 c += gflog[s->v[j].x + 1];
241 if (c >= 0xff)
242 c -= 0xff;
243 ci += gflog[(s->v[i].x + 1) ^ (s->v[j].x + 1)];
244 if (ci >= 0xff)
245 ci -= 0xff;
246 }
247 if (ci > c)
248 c += 0xff;
249 c -= ci;
250 v[i] = c;
251 }
252
253 /* --- Grind through the shares --- */
254
255 for (i = 0; i < s->sz; i++) {
256 unsigned x = 0;
257 for (j = 0; j < s->t; j++) {
258 if (s->v[j].y[i])
259 x ^= gfexp[v[j] + gflog[s->v[j].y[i]]];
260 }
261 buf[i] = x;
262 }
263
264 XS_FREE(v);
265}
266
267/*----- Test rig ----------------------------------------------------------*/
268
269#ifdef TEST_RIG
270
271#include "fibrand.h"
272
273static 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
332int 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 -------------------------------------------------*/