Skip to content

Commit 2f5ff9d

Browse files
author
christos
committed
add arc4random_{buf,uniform}, from OpenBSD.
1 parent d25ca22 commit 2f5ff9d

File tree

3 files changed

+114
-33
lines changed

3 files changed

+114
-33
lines changed

include/stdlib.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: stdlib.h,v 1.94 2010/12/22 19:47:56 jruoho Exp $ */
1+
/* $NetBSD: stdlib.h,v 1.95 2011/02/04 22:07:07 christos Exp $ */
22

33
/*-
44
* Copyright (c) 1990, 1993
@@ -250,6 +250,8 @@ void *alloca(size_t);
250250

251251
uint32_t arc4random(void);
252252
void arc4random_stir(void);
253+
void arc4random_buf(void *, size_t);
254+
uint32_t arc4random_uniform(uint32_t);
253255
void arc4random_addrandom(u_char *, int);
254256
char *getbsize(int *, long *);
255257
char *cgetcap(char *, const char *, int);

lib/libc/gen/arc4random.3

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.\" $NetBSD: arc4random.3,v 1.7 2005/12/26 19:40:14 perry Exp $
1+
.\" $NetBSD: arc4random.3,v 1.8 2011/02/04 22:07:07 christos Exp $
22
.\" $OpenBSD: arc4random.3,v 1.17 2000/12/21 14:07:41 aaron Exp $
33
.\"
44
.\" Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
@@ -31,11 +31,13 @@
3131
.\"
3232
.\" Manual page, using -mandoc macros
3333
.\"
34-
.Dd April 15, 1997
34+
.Dd February 4, 2011
3535
.Dt ARC4RANDOM 3
3636
.Os
3737
.Sh NAME
3838
.Nm arc4random ,
39+
.Nm arc4random_buf ,
40+
.Nm arc4random_uniform ,
3941
.Nm arc4random_stir ,
4042
.Nm arc4random_addrandom
4143
.Nd arc4 random number generator
@@ -46,6 +48,10 @@
4648
.Ft uint32_t
4749
.Fn arc4random "void"
4850
.Ft void
51+
.Fn arc4random_buf "void *buffer" "size_t length"
52+
.Ft uint32_t
53+
.Fn arc4random_uniform "uint32_t upper_bound"
54+
.Ft void
4955
.Fn arc4random_stir "void"
5056
.Ft void
5157
.Fn arc4random_addrandom "u_char *dat" "int datlen"
@@ -76,6 +82,20 @@ versus the fast but poor quality interfaces described in
7682
and
7783
.Xr drand48 3 .
7884
.Pp
85+
The
86+
.Fn arc4random_buf
87+
function fills the
88+
.Fa buffer
89+
with
90+
.Fa length
91+
bytes of ARC4-derived random data.
92+
.Pp
93+
The
94+
.Fn arc4random_uniform
95+
function returns a uniformly distributed random number less than
96+
.Fa upper_bound
97+
avoiding modulo bias when the upper bound is not a power of two.
98+
.Pp
7999
The
80100
.Fn arc4random_stir
81101
function reads data from

lib/libc/gen/arc4random.c

Lines changed: 89 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: arc4random.c,v 1.9 2005/12/24 21:11:16 perry Exp $ */
1+
/* $NetBSD: arc4random.c,v 1.10 2011/02/04 22:07:07 christos Exp $ */
22
/* $OpenBSD: arc4random.c,v 1.6 2001/06/05 05:05:38 pvalchev Exp $ */
33

44
/*
@@ -27,7 +27,7 @@
2727

2828
#include <sys/cdefs.h>
2929
#if defined(LIBC_SCCS) && !defined(lint)
30-
__RCSID("$NetBSD: arc4random.c,v 1.9 2005/12/24 21:11:16 perry Exp $");
30+
__RCSID("$NetBSD: arc4random.c,v 1.10 2011/02/04 22:07:07 christos Exp $");
3131
#endif /* LIBC_SCCS and not lint */
3232

3333
#include "namespace.h"
@@ -44,9 +44,9 @@ __weak_alias(arc4random,_arc4random)
4444
#endif
4545

4646
struct arc4_stream {
47-
u_int8_t i;
48-
u_int8_t j;
49-
u_int8_t s[256];
47+
uint8_t i;
48+
uint8_t j;
49+
uint8_t s[256];
5050
};
5151

5252
static int rs_initialized;
@@ -55,12 +55,11 @@ static struct arc4_stream rs;
5555
static inline void arc4_init(struct arc4_stream *);
5656
static inline void arc4_addrandom(struct arc4_stream *, u_char *, int);
5757
static void arc4_stir(struct arc4_stream *);
58-
static inline u_int8_t arc4_getbyte(struct arc4_stream *);
59-
static inline u_int32_t arc4_getword(struct arc4_stream *);
58+
static inline uint8_t arc4_getbyte(struct arc4_stream *);
59+
static inline uint32_t arc4_getword(struct arc4_stream *);
6060

6161
static inline void
62-
arc4_init(as)
63-
struct arc4_stream *as;
62+
arc4_init(struct arc4_stream *as)
6463
{
6564
int n;
6665

@@ -71,13 +70,10 @@ arc4_init(as)
7170
}
7271

7372
static inline void
74-
arc4_addrandom(as, dat, datlen)
75-
struct arc4_stream *as;
76-
u_char *dat;
77-
int datlen;
73+
arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen)
7874
{
7975
int n;
80-
u_int8_t si;
76+
uint8_t si;
8177

8278
as->i--;
8379
for (n = 0; n < 256; n++) {
@@ -91,8 +87,7 @@ arc4_addrandom(as, dat, datlen)
9187
}
9288

9389
static void
94-
arc4_stir(as)
95-
struct arc4_stream *as;
90+
arc4_stir(struct arc4_stream *as)
9691
{
9792
int fd;
9893
struct {
@@ -140,11 +135,10 @@ arc4_stir(as)
140135
arc4_getbyte(as);
141136
}
142137

143-
static inline u_int8_t
144-
arc4_getbyte(as)
145-
struct arc4_stream *as;
138+
static inline uint8_t
139+
arc4_getbyte(struct arc4_stream *as)
146140
{
147-
u_int8_t si, sj;
141+
uint8_t si, sj;
148142

149143
as->i = (as->i + 1);
150144
si = as->s[as->i];
@@ -155,11 +149,10 @@ arc4_getbyte(as)
155149
return (as->s[(si + sj) & 0xff]);
156150
}
157151

158-
static inline u_int32_t
159-
arc4_getword(as)
160-
struct arc4_stream *as;
152+
static inline uint32_t
153+
arc4_getword(struct arc4_stream *as)
161154
{
162-
u_int32_t val;
155+
uint32_t val;
163156
val = arc4_getbyte(as) << 24;
164157
val |= arc4_getbyte(as) << 16;
165158
val |= arc4_getbyte(as) << 8;
@@ -168,7 +161,7 @@ arc4_getword(as)
168161
}
169162

170163
void
171-
arc4random_stir()
164+
arc4random_stir(void)
172165
{
173166
if (!rs_initialized) {
174167
arc4_init(&rs);
@@ -178,23 +171,89 @@ arc4random_stir()
178171
}
179172

180173
void
181-
arc4random_addrandom(dat, datlen)
182-
u_char *dat;
183-
int datlen;
174+
arc4random_addrandom(u_char *dat, int datlen)
184175
{
185176
if (!rs_initialized)
186177
arc4random_stir();
187178
arc4_addrandom(&rs, dat, datlen);
188179
}
189180

190-
u_int32_t
191-
arc4random()
181+
uint32_t
182+
arc4random(void)
192183
{
193184
if (!rs_initialized)
194185
arc4random_stir();
195186
return arc4_getword(&rs);
196187
}
197188

189+
void
190+
arc4random_buf(void *buf, size_t len)
191+
{
192+
uint8_t *bp = buf;
193+
uint8_t *ep = bp + len;
194+
195+
bp[0] = arc4_getbyte(&rs) % 3;
196+
while (bp[0]--)
197+
(void)arc4_getbyte(&rs);
198+
199+
while (bp < ep)
200+
*bp++ = arc4_getbyte(&rs);
201+
}
202+
203+
/*-
204+
* Written by Damien Miller.
205+
* With simplifications by Jinmei Tatuya.
206+
*/
207+
208+
/*
209+
* Calculate a uniformly distributed random number less than
210+
* upper_bound avoiding "modulo bias".
211+
*
212+
* Uniformity is achieved by generating new random numbers
213+
* until the one returned is outside the range
214+
* [0, 2^32 % upper_bound[. This guarantees the selected
215+
* random number will be inside the range
216+
* [2^32 % upper_bound, 2^32[ which maps back to
217+
* [0, upper_bound[ after reduction modulo upper_bound.
218+
*/
219+
uint32_t
220+
arc4random_uniform(uint32_t upper_bound)
221+
{
222+
uint32_t r, min;
223+
224+
if (upper_bound < 2)
225+
return 0;
226+
227+
#if defined(ULONG_MAX) && (ULONG_MAX > 0xFFFFFFFFUL)
228+
min = 0x100000000UL % upper_bound;
229+
#else
230+
/* calculate (2^32 % upper_bound) avoiding 64-bit math */
231+
if (upper_bound > 0x80000000U)
232+
/* 2^32 - upper_bound (only one "value area") */
233+
min = 1 + ~upper_bound;
234+
else
235+
/* ((2^32 - x) % x) == (2^32 % x) when x <= 2^31 */
236+
min = (0xFFFFFFFFU - upper_bound + 1) % upper_bound;
237+
#endif
238+
239+
/*
240+
* This could theoretically loop forever but each retry has
241+
* p > 0.5 (worst case, usually far better) of selecting a
242+
* number inside the range we need, so it should rarely need
243+
* to re-roll (at all).
244+
*/
245+
if (!rs_initialized)
246+
arc4random_stir();
247+
if (arc4_getbyte(&rs) & 1)
248+
(void)arc4_getbyte(&rs);
249+
do
250+
r = arc4_getword(&rs);
251+
while (r < min);
252+
253+
return r % upper_bound;
254+
}
255+
256+
198257
#if 0
199258
/*-------- Test code for i386 --------*/
200259
#include <stdio.h>

0 commit comments

Comments
 (0)