Files
palladum-lightning/common/pseudorand.c
2025-11-13 21:21:29 +10:30

105 lines
2.2 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "config.h"
#include <assert.h>
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/isaac/isaac64.h>
#include <ccan/tal/tal.h>
#include <common/pseudorand.h>
#include <common/randbytes.h>
static struct isaac64_ctx isaac64;
static struct siphash_seed siphashseed;
static bool pseudorand_initted = false;
static void init_if_needed(void)
{
if (unlikely(!pseudorand_initted)) {
unsigned char seedbuf[16];
struct sha256 sha;
randbytes(seedbuf, sizeof(seedbuf));
memcpy(&siphashseed, seedbuf, sizeof(siphashseed));
/* In case isaac is reversible, don't leak seed. */
sha256(&sha, seedbuf, sizeof(seedbuf));
isaac64_init(&isaac64, sha.u.u8, sizeof(sha.u.u8));
pseudorand_initted = true;
}
}
uint64_t pseudorand_(uint64_t max, uint64_t *offset)
{
init_if_needed();
assert(max);
/* We try to avoid being order-dependent here. */
if (randbytes_overridden()) {
uint64_t rand;
randbytes_(&rand, sizeof(rand), offset);
return rand % max;
}
return isaac64_next_uint(&isaac64, max);
}
uint64_t pseudorand_u64_(uint64_t *offset)
{
init_if_needed();
if (randbytes_overridden()) {
uint64_t rand;
randbytes_(&rand, sizeof(rand), offset);
return rand;
}
return isaac64_next_uint64(&isaac64);
}
double pseudorand_double_(uint64_t *offset)
{
init_if_needed();
if (randbytes_overridden()) {
uint64_t rand;
randbytes_(&rand, sizeof(rand), offset);
return rand / (double)UINT64_MAX;
}
return isaac64_next_double(&isaac64);
}
const struct siphash_seed *siphash_seed(void)
{
init_if_needed();
return &siphashseed;
}
void tal_arr_randomize_(void *arr, size_t elemsize)
{
/* Easier arith. */
char *carr = arr;
size_t n = tal_bytelen(arr) / elemsize;
assert(tal_bytelen(arr) % elemsize == 0);
/* From Wikipedia's Fischer-Yates shuffle article:
*
* for i from 0 to n2 do
* j ← random integer such that i ≤ j < n
* exchange a[i] and a[j]
*/
if (n < 2)
return;
for (size_t i = 0; i < n - 1; i++) {
size_t j = i + pseudorand(n - i);
char tmp[elemsize];
/* Technically, memcpy in place is undefined (src and dest overlap). */
if (j == i)
continue;
memcpy(tmp, carr + i * elemsize, elemsize);
memcpy(carr + i * elemsize, carr + j * elemsize, elemsize);
memcpy(carr + j * elemsize, tmp, elemsize);
}
}