chiark / gitweb /
Merge branch '2.4.x' into 2.5.x
[catacomb] / pub / bbs-rand.c
1 /* -*-c-*-
2  *
3  * Blum-Blum-Shub secure random number generator
4  *
5  * (c) 1999 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 <stdarg.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <mLib/bits.h>
35 #include <mLib/sub.h>
36
37 #include "arena.h"
38 #include "bbs.h"
39 #include "grand.h"
40 #include "mp.h"
41 #include "mpbarrett.h"
42 #include "mpint.h"
43 #include "mprand.h"
44 #include "paranoia.h"
45
46 /*----- Main code ---------------------------------------------------------*/
47
48 /* --- @bbs_create@ --- *
49  *
50  * Arguments:   @bbs *b@ = pointer to BBS generator state to initialize
51  *              @mp *m@ = modulus (must be a Blum integer)
52  *              @mp *x@ = initial seed for generator
53  *
54  * Returns:     ---
55  *
56  * Use:         Initializes a BBS generator.  The generator is stepped once
57  *              after initialization, as for @bbs_seed@.
58  */
59
60 void bbs_create(bbs *b, mp *m, mp *x)
61 {
62   mpw kw;
63   mp k;
64
65   mpbarrett_create(&b->mb, m);
66   kw = mp_bits(m) - 1;
67   mp_build(&k, &kw, &kw + 1);
68   b->k = mp_bits(&k) - 1;
69   b->x = 0;
70   bbs_seed(b, x);
71 }
72
73 /* --- @bbs_destroy@ --- *
74  *
75  * Arguments:   @bbs *b@ = pointer to BBS generator state
76  *
77  * Returns:     ---
78  *
79  * Use:         Destroys a generator state when it's no longer wanted.
80  */
81
82 void bbs_destroy(bbs *b)
83 {
84   mp_drop(b->x);
85   mpbarrett_destroy(&b->mb);
86 }
87
88 /* --- @bbs_step@ --- *
89  *
90  * Arguments:   @bbs *b@ = pointer to BBS generator state
91  *
92  * Returns:     ---
93  *
94  * Use:         Steps the generator once.  This isn't too useful in client
95  *              code.
96  */
97
98 void bbs_step(bbs *b)
99 {
100   mp *x = b->x;
101   x = mp_sqr(x, x);
102   x = mpbarrett_reduce(&b->mb, x, x);
103   b->x = x;
104   b->b = b->k;
105   b->r = b->x->v[0];
106 }
107
108 /* --- @bbs_set@ --- *
109  *
110  * Arguments:   @bbs *b@ = pointer to BBS generator state
111  *              @mp *x@ = new residue to set
112  *
113  * Returns:     ---
114  *
115  * Use:         Sets a new quadratic residue.  The generator is stepped once.
116  */
117
118 void bbs_set(bbs *b, mp *x)
119 {
120   mp_drop(b->x);
121   b->x = MP_COPY(x);
122   bbs_step(b);
123 }
124
125 /* --- @bbs_seed@ --- *
126  *
127  * Arguments:   @bbs *b@ = pointer to BBS generator state
128  *              @mp *x@ = new seed to set
129  *
130  * Returns      ---
131  *
132  * Use:         Sets a new seed.  The generator is stepped until the residue
133  *              has clearly wrapped around.
134  */
135
136 void bbs_seed(bbs *b, mp *x)
137 {
138   mp *y;
139   x = MP_COPY(x);
140   for (;;) {
141     y = mp_sqr(MP_NEW, x);
142     y = mpbarrett_reduce(&b->mb, y, y);
143     if (MP_CMP(y, <, x))
144       break;
145     mp_drop(x);
146     x = y;
147   }
148   mp_drop(x);
149   bbs_set(b, y);
150   mp_drop(y);
151 }
152
153 /* --- @bbs_bits@ --- *
154  *
155  * Arguments:   @bbs *b@ = pointer to BBS generator state
156  *              @unsigned bits@ = number of bits wanted
157  *
158  * Returns:     Bits extracted from the BBS generator.
159  *
160  * Use:         Extracts a requested number of bits from the BBS generator.
161  */
162
163 uint32 bbs_bits(bbs *b, unsigned bits)
164 {
165   uint32 x = 0;
166   mpw m;
167
168   /* --- Keep turning the handle until there's enough in the reservoir --- */
169
170   while (bits >= b->b) {
171     bits -= b->b;
172     m = (1 << b->b) - 1;
173     x |= (b->r & m) << bits;
174     bbs_step(b);
175   }
176
177   /* --- Extract the last few bits needed --- */
178
179   if (bits) {
180     m = (1 << bits) - 1;
181     b->b -= bits;
182     x |= (b->r >> b->b) & m;
183   }
184
185   /* --- Done --- */
186
187   return (x);
188 }
189
190 /* --- @bbs_wrap@ --- *
191  *
192  * Arguments:   @bbs *b@ = pointer to BBS generator state
193  *
194  * Returns:     ---
195  *
196  * Use:         Steps the generator if any of the reservoir bits are used.
197  *              This can be used to `wrap up' after a Blum-Goldwasser
198  *              encryption, for example, producing the final value to be sent
199  *              along with the ciphertext.
200  *
201  *              If a generator is seeded, %$b$% bits are extracted, and then
202  *              @bbs_wrap@ is called, the generator will have been stepped
203  *              %$\lceil b/k \rceil$% times.
204  */
205
206 void bbs_wrap(bbs *b)
207 {
208   if (b->b < b->k)
209     bbs_step(b);
210 }
211
212 /*----- Generic random number generator interface -------------------------*/
213
214 typedef struct gctx {
215   grand r;
216   bbs b;
217 } gctx;
218
219 static void gdestroy(grand *r)
220 {
221   gctx *g = (gctx *)r;
222   bbs_destroy(&g->b);
223   BURN(*g);
224   S_DESTROY(g);
225 }
226
227 static int gmisc(grand *r, unsigned op, ...)
228 {
229   gctx *g = (gctx *)r;
230   va_list ap;
231   int rc = 0;
232   va_start(ap, op);
233
234   switch (op) {
235     case GRAND_CHECK:
236       switch (va_arg(ap, unsigned)) {
237         case GRAND_CHECK:
238         case GRAND_SEEDINT:
239         case GRAND_SEEDUINT32:
240         case GRAND_SEEDMP:
241         case GRAND_SEEDRAND:
242         case BBS_SET:
243         case BBS_STEP:
244         case BBS_STEPSZ:
245         case BBS_BITS:
246         case BBS_WRAP:
247         case BBS_FF:
248         case BBS_FFN:
249         case BBS_REW:
250         case BBS_REWN:
251         case BBS_MOD:
252         case BBS_STATE:
253           rc = 1;
254           break;
255         default:
256           rc = 0;
257           break;
258       }
259       break;
260     case GRAND_SEEDINT: {
261       mp *x = mp_fromuint(MP_NEW, va_arg(ap, unsigned));
262       bbs_seed(&g->b, x);
263       mp_drop(x);
264     } break;
265     case GRAND_SEEDUINT32: {
266       mp *x = mp_fromuint32(MP_NEW, va_arg(ap, uint32));
267       bbs_seed(&g->b, x);
268       mp_drop(x);
269     } break;
270     case GRAND_SEEDMP:
271       bbs_seed(&g->b, va_arg(ap, mp *));
272       break;
273     case GRAND_SEEDRAND: {
274       grand *rr = va_arg(ap, grand *);
275       mp *m = mprand(MP_NEW, mp_bits(g->b.mb.m) - 1, rr, 0);
276       bbs_seed(&g->b, m);
277       mp_drop(m);
278     } break;
279     case BBS_SET:
280       bbs_set(&g->b, va_arg(ap, mp *));
281       break;
282     case BBS_STEP:
283       bbs_step(&g->b);
284       break;
285     case BBS_STEPSZ:
286       rc = g->b.k;
287       break;
288     case BBS_BITS: {
289       unsigned nb = va_arg(ap, unsigned);
290       uint32 *w = va_arg(ap, uint32 *);
291       *w = bbs_bits(&g->b, nb);
292     } break;
293     case BBS_WRAP:
294       bbs_wrap(&g->b);
295       break;
296     case BBS_FF: {
297       const bbs_priv *bp = va_arg(ap, const bbs_priv *);
298       mp *n = va_arg(ap, mp *);
299       bbs_ff(&g->b, bp, n);
300     } break;
301     case BBS_FFN: {
302       const bbs_priv *bp = va_arg(ap, const bbs_priv *);
303       unsigned long n = va_arg(ap, unsigned long);
304       bbs_ffn(&g->b, bp, n);
305     } break;
306     case BBS_REW: {
307       const bbs_priv *bp = va_arg(ap, const bbs_priv *);
308       mp *n = va_arg(ap, mp *);
309       bbs_rew(&g->b, bp, n);
310     } break;
311     case BBS_REWN: {
312       const bbs_priv *bp = va_arg(ap, const bbs_priv *);
313       unsigned long n = va_arg(ap, unsigned long);
314       bbs_rewn(&g->b, bp, n);
315     } break;
316     case BBS_MOD: {
317       mp **n = va_arg(ap, mp **);
318       if (*n) MP_DROP(*n);
319       *n = MP_COPY(g->b.mb.m);
320     } break;
321     case BBS_STATE: {
322       mp **n = va_arg(ap, mp **);
323       if (*n) MP_DROP(*n);
324       *n = MP_COPY(g->b.x);
325     } break;
326     default:
327       GRAND_BADOP;
328       break;
329   }
330
331   va_end(ap);
332   return (rc);
333 }
334
335 static octet gbyte(grand *r)
336 {
337   gctx *g = (gctx *)r;
338   return (bbs_bits(&g->b, 8));
339 }
340
341 static uint32 gword(grand *r)
342 {
343   gctx *g = (gctx *)r;
344   return (bbs_bits(&g->b, 32));
345 }
346
347 static const grand_ops gops = {
348   "bbs",
349   GRAND_CRYPTO, 0,
350   gmisc, gdestroy,
351   gword, gbyte, gword, grand_defaultrange, grand_defaultfill
352 };
353
354 /* --- @bbs_rand@ --- *
355  *
356  * Arguments:   @mp *m@ = modulus
357  *              @mp *x@ = initial seed
358  *
359  * Returns:     Pointer to a generic generator.
360  *
361  * Use:         Constructs a generic generator interface over a
362  *              Blum-Blum-Shub generator.
363  */
364
365 grand *bbs_rand(mp *m, mp *x)
366 {
367   gctx *g = S_CREATE(gctx);
368   g->r.ops = &gops;
369   bbs_create(&g->b, m, x);
370   return (&g->r);
371 }
372
373 /*----- Test rig ----------------------------------------------------------*/
374
375 #ifdef TEST_RIG
376
377 static int verify(dstr *v)
378 {
379   mp *n = *(mp **)v[0].buf;
380   mp *x = *(mp **)v[1].buf;
381   grand *b = bbs_rand(n, x);
382   dstr d = DSTR_INIT;
383   int ok = 1;
384
385   dstr_ensure(&d, v[2].len);
386   b->ops->fill(b, d.buf, v[2].len);
387   d.len = v[2].len;
388   if (memcmp(d.buf, v[2].buf, v[2].len) != 0) {
389     fputs("\n*** bbs failure\n", stderr);
390     fputs("n = ", stderr); mp_writefile(n, stderr, 10); fputc('\n', stderr);
391     fputs("x = ", stderr); mp_writefile(x, stderr, 10); fputc('\n', stderr);
392     fputs("expected = ", stderr); type_hex.dump(&v[2], stderr);
393     fputc('\n', stderr);
394     fputs("   found = ", stderr); type_hex.dump(&d, stderr);
395     fputc('\n', stderr);
396     fprintf(stderr, "k = %u\n", ((gctx *)b)->b.k);
397     ok = 0;
398   }
399   b->ops->destroy(b);
400   mp_drop(x);
401   mp_drop(n);
402   dstr_destroy(&d);
403   assert(mparena_count(MPARENA_GLOBAL) == 0);
404   return (ok);
405 }
406
407 static test_chunk tests[] = {
408   { "bbs", verify, { &type_mp, &type_mp, &type_hex, 0 } },
409   { 0, 0, { 0 } }
410 };
411
412 int main(int argc, char *argv[])
413 {
414   sub_init();
415   test_run(argc, argv, tests, SRCDIR "/t/bbs");
416   return (0);
417 }
418
419 #endif
420
421 /*----- That's all, folks -------------------------------------------------*/