#define ROTL32(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b))))
#define CHACHA20_QUARTERROUND(A, B, C, D) \
- A += B; \
- D = ROTL32(D ^ A, 16); \
- C += D; \
- B = ROTL32(B ^ C, 12); \
- A += B; \
- D = ROTL32(D ^ A, 8); \
- C += D; \
- B = ROTL32(B ^ C, 7)
+ A += B; \
+ D = ROTL32(D ^ A, 16); \
+ C += D; \
+ B = ROTL32(B ^ C, 12); \
+ A += B; \
+ D = ROTL32(D ^ A, 8); \
+ C += D; \
+ B = ROTL32(B ^ C, 7)
static void CHACHA20_ROUNDS(uint32_t st[16])
{
- int i;
-
- for (i = 0; i < 20; i += 2) {
- CHACHA20_QUARTERROUND(st[0], st[4], st[8], st[12]);
- CHACHA20_QUARTERROUND(st[1], st[5], st[9], st[13]);
- CHACHA20_QUARTERROUND(st[2], st[6], st[10], st[14]);
- CHACHA20_QUARTERROUND(st[3], st[7], st[11], st[15]);
- CHACHA20_QUARTERROUND(st[0], st[5], st[10], st[15]);
- CHACHA20_QUARTERROUND(st[1], st[6], st[11], st[12]);
- CHACHA20_QUARTERROUND(st[2], st[7], st[8], st[13]);
- CHACHA20_QUARTERROUND(st[3], st[4], st[9], st[14]);
- }
+ int i;
+
+ for (i = 0; i < 20; i += 2) {
+ CHACHA20_QUARTERROUND(st[0], st[4], st[8], st[12]);
+ CHACHA20_QUARTERROUND(st[1], st[5], st[9], st[13]);
+ CHACHA20_QUARTERROUND(st[2], st[6], st[10], st[14]);
+ CHACHA20_QUARTERROUND(st[3], st[7], st[11], st[15]);
+ CHACHA20_QUARTERROUND(st[0], st[5], st[10], st[15]);
+ CHACHA20_QUARTERROUND(st[1], st[6], st[11], st[12]);
+ CHACHA20_QUARTERROUND(st[2], st[7], st[8], st[13]);
+ CHACHA20_QUARTERROUND(st[3], st[4], st[9], st[14]);
+ }
}
static void chacha20_update(uint8_t out[CHACHA20_BLOCKBYTES], uint32_t st[16])
{
- uint32_t ks[16];
- int i;
-
- memcpy(ks, st, 4 * 16);
- CHACHA20_ROUNDS(st);
- for (i = 0; i < 16; i++) {
- ks[i] += st[i];
- }
- memcpy(out, ks, CHACHA20_BLOCKBYTES);
- st[12]++;
+ uint32_t ks[16];
+ int i;
+
+ memcpy(ks, st, 4 * 16);
+ CHACHA20_ROUNDS(st);
+ for (i = 0; i < 16; i++) {
+ ks[i] += st[i];
+ }
+ memcpy(out, ks, CHACHA20_BLOCKBYTES);
+ st[12]++;
}
static void chacha20_init(uint32_t st[16], const uint8_t key[CHACHA20_KEYBYTES])
{
- static const uint32_t constants[4] = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
- memcpy(&st[0], constants, 4 * 4);
- memcpy(&st[4], key, CHACHA20_KEYBYTES);
- memset(&st[12], 0, 4 * 4);
+ static const uint32_t constants[4] = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
+ memcpy(&st[0], constants, 4 * 4);
+ memcpy(&st[4], key, CHACHA20_KEYBYTES);
+ memset(&st[12], 0, 4 * 4);
}
static int chacha20_rng(uint8_t* out, size_t len, uint8_t key[CHACHA20_KEYBYTES])
{
- uint32_t st[16];
- size_t off;
-
- chacha20_init(st, key);
- chacha20_update(&out[0], st);
- memcpy(key, out, CHACHA20_KEYBYTES);
- off = 0;
- while (len >= CHACHA20_BLOCKBYTES) {
- chacha20_update(&out[off], st);
- len -= CHACHA20_BLOCKBYTES;
- off += CHACHA20_BLOCKBYTES;
- }
- if (len > 0) {
- uint8_t tmp[CHACHA20_BLOCKBYTES];
- chacha20_update(tmp, st);
- memcpy(&out[off], tmp, len);
- }
- return 0;
+ uint32_t st[16];
+ size_t off;
+
+ chacha20_init(st, key);
+ chacha20_update(&out[0], st);
+ memcpy(key, out, CHACHA20_KEYBYTES);
+ off = 0;
+ while (len >= CHACHA20_BLOCKBYTES) {
+ chacha20_update(&out[off], st);
+ len -= CHACHA20_BLOCKBYTES;
+ off += CHACHA20_BLOCKBYTES;
+ }
+ if (len > 0) {
+ uint8_t tmp[CHACHA20_BLOCKBYTES];
+ chacha20_update(tmp, st);
+ memcpy(&out[off], tmp, len);
+ }
+ return 0;
}
struct rng_state {
- int initialized;
- size_t off;
- uint8_t key[CHACHA20_KEYBYTES];
- uint8_t reserve[RNG_RESERVE_LEN];
+ int initialized;
+ size_t off;
+ uint8_t key[CHACHA20_KEYBYTES];
+ uint8_t reserve[RNG_RESERVE_LEN];
};
void arc4random_buf(void* buffer, size_t len)
{
- static _Thread_local struct rng_state rng_state;
-
- unsigned char* buffer_ = (unsigned char*)buffer;
- size_t off;
- size_t remaining;
- size_t partial;
-
- if (!rng_state.initialized) {
- if (getentropy(rng_state.key, sizeof rng_state.key) != 0) {
- assert(0);
- }
- rng_state.off = RNG_RESERVE_LEN;
- rng_state.initialized = 1;
- }
- off = 0;
- remaining = len;
- while (remaining > 0) {
- if (rng_state.off == RNG_RESERVE_LEN) {
- while (remaining >= RNG_RESERVE_LEN) {
- chacha20_rng(&buffer_[off], RNG_RESERVE_LEN, rng_state.key);
- off += RNG_RESERVE_LEN;
- remaining -= RNG_RESERVE_LEN;
- }
- if (remaining == 0) {
- break;
- }
- chacha20_rng(&rng_state.reserve[0], RNG_RESERVE_LEN, rng_state.key);
- rng_state.off = 0;
- }
- partial = RNG_RESERVE_LEN - rng_state.off;
- if (remaining < partial) {
- partial = remaining;
- }
- memcpy(&buffer_[off], &rng_state.reserve[rng_state.off], partial);
- memset(&rng_state.reserve[rng_state.off], 0, partial);
- rng_state.off += partial;
- remaining -= partial;
- off += partial;
- }
+ static _Thread_local struct rng_state rng_state;
+
+ unsigned char* buffer_ = (unsigned char*)buffer;
+ size_t off;
+ size_t remaining;
+ size_t partial;
+
+ if (!rng_state.initialized) {
+ if (getentropy(rng_state.key, sizeof rng_state.key) != 0) {
+ assert(0);
+ }
+ rng_state.off = RNG_RESERVE_LEN;
+ rng_state.initialized = 1;
+ }
+ off = 0;
+ remaining = len;
+ while (remaining > 0) {
+ if (rng_state.off == RNG_RESERVE_LEN) {
+ while (remaining >= RNG_RESERVE_LEN) {
+ chacha20_rng(&buffer_[off], RNG_RESERVE_LEN, rng_state.key);
+ off += RNG_RESERVE_LEN;
+ remaining -= RNG_RESERVE_LEN;
+ }
+ if (remaining == 0) {
+ break;
+ }
+ chacha20_rng(&rng_state.reserve[0], RNG_RESERVE_LEN, rng_state.key);
+ rng_state.off = 0;
+ }
+ partial = RNG_RESERVE_LEN - rng_state.off;
+ if (remaining < partial) {
+ partial = remaining;
+ }
+ memcpy(&buffer_[off], &rng_state.reserve[rng_state.off], partial);
+ memset(&rng_state.reserve[rng_state.off], 0, partial);
+ rng_state.off += partial;
+ remaining -= partial;
+ off += partial;
+ }
}
uint32_t arc4random(void)
{
- uint32_t v;
+ uint32_t v;
- arc4random_buf(&v, sizeof v);
+ arc4random_buf(&v, sizeof v);
- return v;
+ return v;
}
uint32_t arc4random_uniform(const uint32_t upper_bound)
{
- uint32_t min;
- uint32_t r;
-
- if (upper_bound < 2U) {
- return 0;
- }
- min = (1U + ~upper_bound) % upper_bound; /* = 2**32 mod upper_bound */
- do {
- r = arc4random();
- } while (r < min);
- /* r is now clamped to a set whose size mod upper_bound == 0
- * the worst case (2**31+1) requires 2 attempts on average */
-
- return r % upper_bound;
+ uint32_t min;
+ uint32_t r;
+
+ if (upper_bound < 2U) {
+ return 0;
+ }
+ min = (1U + ~upper_bound) % upper_bound; // = 2**32 mod upper_bound
+ do {
+ r = arc4random();
+ } while (r < min);
+
+ // r is now clamped to a set whose size mod upper_bound == 0.
+ // The worst case (2**31+1) requires 2 attempts on average.
+
+ return r % upper_bound;
}