3 * $Id: bbs-rand.c,v 1.2 1999/12/13 15:34:01 mdw Exp $
5 * Blum-Blum-Shub secure random number generator
7 * (c) 1999 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 --------------------------------------------------*
32 * $Log: bbs-rand.c,v $
33 * Revision 1.2 1999/12/13 15:34:01 mdw
34 * Add support for seeding from a generic pseudorandom source.
36 * Revision 1.1 1999/12/10 23:14:59 mdw
37 * Blum-Blum-Shub generator, and Blum-Goldwasser encryption.
41 /*----- Header files ------------------------------------------------------*/
47 #include <mLib/bits.h>
53 #include "mpbarrett.h"
57 /*----- Main code ---------------------------------------------------------*/
59 /* --- @bbs_create@ --- *
61 * Arguments: @bbs *b@ = pointer to BBS generator state to initialize
62 * @mp *m@ = modulus (must be a Blum integer)
63 * @mp *x@ = initial seed for generator
67 * Use: Initializes a BBS generator. The generator is stepped once
68 * after initialization, as for @bbs_seed@.
71 void bbs_create(bbs
*b
, mp
*m
, mp
*x
)
76 mpbarrett_create(&b
->mb
, m
);
78 mp_build(&k
, &kw
, &kw
+ 1);
79 b
->k
= mp_bits(&k
) - 1;
84 /* --- @bbs_destroy@ --- *
86 * Arguments: @bbs *b@ = pointer to BBS generator state
90 * Use: Destroys a generator state when it's no longer wanted.
93 void bbs_destroy(bbs
*b
)
96 mpbarrett_destroy(&b
->mb
);
99 /* --- @bbs_step@ --- *
101 * Arguments: @bbs *b@ = pointer to BBS generator state
105 * Use: Steps the generator once. This isn't too useful in client
109 void bbs_step(bbs
*b
)
113 x
= mpbarrett_reduce(&b
->mb
, x
, x
);
119 /* --- @bbs_set@ --- *
121 * Arguments: @bbs *b@ = pointer to BBS generator state
122 * @mp *x@ = new residue to set
126 * Use: Sets a new quadratic residue. The generator is stepped once.
129 void bbs_set(bbs
*b
, mp
*x
)
137 /* --- @bbs_seed@ --- *
139 * Arguments: @bbs *b@ = pointer to BBS generator state
140 * @mp *x@ = new seed to set
144 * Use: Sets a new seed. The generator is stepped until the residue
145 * has clearly wrapped around.
148 void bbs_seed(bbs
*b
, mp
*x
)
153 y
= mp_sqr(MP_NEW
, x
);
154 y
= mpbarrett_reduce(&b
->mb
, y
, y
);
165 /* --- @bbs_bits@ --- *
167 * Arguments: @bbs *b@ = pointer to BBS generator state
168 * @unsigned bits@ = number of bits wanted
170 * Returns: Bits extracted from the BBS generator.
172 * Use: Extracts a requested number of bits from the BBS generator.
175 uint32
bbs_bits(bbs
*b
, unsigned bits
)
180 /* --- Keep turning the handle until there's enough in the reservoir --- */
182 while (bits
>= b
->b
) {
185 x
|= (b
->r
& m
) << bits
;
189 /* --- Extract the last few bits needed --- */
194 x
|= (b
->r
>> b
->b
) & m
;
202 /* --- @bbs_wrap@ --- *
204 * Arguments: @bbs *b@ = pointer to BBS generator state
208 * Use: Steps the generator if any of the reservoir bits are used.
209 * This can be used to `wrap up' after a Blum-Goldwasser
210 * encryption, for example, producing the final value to be sent
211 * along with the ciphertext.
213 * If a generator is seeded, %$b$% bits are extracted, and then
214 * @bbs_wrap@ is called, the generator will have been stepped
215 * %$\lceil b/k \rceil% times.
218 void bbs_wrap(bbs
*b
)
224 /*----- Generic random number generator interface -------------------------*/
226 typedef struct gctx
{
231 static void gdestroy(grand
*r
)
238 static int gmisc(grand
*r
, unsigned op
, ...)
247 switch (va_arg(ap
, unsigned)) {
250 case GRAND_SEEDUINT32
:
261 case GRAND_SEEDINT
: {
262 mp
*x
= mp_fromuint(MP_NEW
, va_arg(ap
, unsigned));
266 case GRAND_SEEDUINT32
: {
267 mp
*x
= mp_fromuint32(MP_NEW
, va_arg(ap
, uint32
));
272 bbs_seed(&g
->b
, va_arg(ap
, mp
*));
274 case GRAND_SEEDRAND
: {
275 grand
*rr
= va_arg(ap
, grand
*);
276 mp
*m
= mprand(MP_NEW
, mp_bits(g
->b
.mb
.m
) - 1, rr
, 0);
281 bbs_set(&g
->b
, va_arg(ap
, mp
*));
292 static octet
gbyte(grand
*r
)
295 return (bbs_bits(&g
->b
, 8));
298 static uint32
gword(grand
*r
)
301 return (bbs_bits(&g
->b
, 32));
304 static const grand_ops gops
= {
308 gword
, gbyte
, gword
, grand_range
, grand_fill
311 /* --- @bbs_rand@ --- *
313 * Arguments: @mp *m@ = modulus
314 * @mp *x@ = initial seed
316 * Returns: Pointer to a generic generator.
318 * Use: Constructs a generic generator interface over a
319 * Blum-Blum-Shub generator.
322 grand
*bbs_rand(mp
*m
, mp
*x
)
324 gctx
*g
= CREATE(gctx
);
326 bbs_create(&g
->b
, m
, x
);
330 /*----- Test rig ----------------------------------------------------------*/
334 static int verify(dstr
*v
)
336 mp
*n
= *(mp
**)v
[0].buf
;
337 mp
*x
= *(mp
**)v
[1].buf
;
338 grand
*b
= bbs_rand(n
, x
);
342 dstr_ensure(&d
, v
[2].len
);
343 b
->ops
->fill(b
, d
.buf
, v
[2].len
);
345 if (memcmp(d
.buf
, v
[2].buf
, v
[2].len
) != 0) {
346 fputs("\n*** bbs failure\n", stderr
);
347 fputs("n = ", stderr
); mp_writefile(n
, stderr
, 10); fputc('\n', stderr
);
348 fputs("x = ", stderr
); mp_writefile(x
, stderr
, 10); fputc('\n', stderr
);
349 fputs("expected = ", stderr
); type_hex
.dump(&v
[2], stderr
);
351 fputs(" found = ", stderr
); type_hex
.dump(&d
, stderr
);
353 fprintf(stderr
, "k = %u\n", ((gctx
*)b
)->b
.k
);
360 assert(mparena_count(MPARENA_GLOBAL
) == 0);
364 static test_chunk tests
[] = {
365 { "bbs", verify
, { &type_mp
, &type_mp
, &type_hex
, 0 } },
369 int main(int argc
, char *argv
[])
372 test_run(argc
, argv
, tests
, SRCDIR
"/tests/bbs");
378 /*----- That's all, folks -------------------------------------------------*/