#endif
+/* Number of elements in master_state array. */
+#define SZU64 (sizeof (master_state) / sizeof (uint64_t))
-static void
-scramble_seed (unsigned char *dest, unsigned char *src, int size)
-{
- int i;
- for (i = 0; i < size; i++)
- dest[(i % 2) * (size / 2) + i / 2] = src[i];
-}
+/* Keys for scrambling the seed in order to avoid poor seeds. */
+static const uint64_t xor_keys[] = {
+ 0xbd0c5b6e50c2df49ULL, 0xd46061cd46e1df38ULL, 0xbb4f4d4ed6103544ULL,
+ 0x114a583d0756ad39ULL, 0x4b5ad8623d0aaab6ULL, 0x3f2ed7afbe0c0f21ULL,
+ 0xdec83fd65f113445ULL, 0x3824f8fbc4f10d24ULL, 0x5d9025af05878911ULL,
+ 0x500bc46b540340e9ULL, 0x8bd53298e0d00530ULL, 0x57886e40a952e06aULL,
+ 0x926e76c88e31cdb6ULL, 0xbd0724dac0a3a5f9ULL, 0xc5c8981b858ab796ULL,
+ 0xbb12ab2694c2b32cULL
+};
+
+
+/* Since a XOR cipher is symmetric, we need only one routine, and we
+ can use it both for encryption and decryption. */
static void
-unscramble_seed (unsigned char *dest, unsigned char *src, int size)
+scramble_seed (uint64_t *dest, const uint64_t *src)
{
- int i;
-
- for (i = 0; i < size; i++)
- dest[i] = src[(i % 2) * (size / 2) + i / 2];
+ for (int i = 0; i < (int) SZU64; i++)
+ dest[i] = src[i] ^ xor_keys[i];
}
-
/* random_seed is used to seed the PRNG with either a default
set of seeds or user specified set of seeds. random_seed
must be called with no argument or exactly one argument. */
void
random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get)
{
- unsigned char seed[sizeof (master_state)];
+ uint64_t seed[SZU64];
#define SZ (sizeof (master_state) / sizeof (GFC_INTEGER_4))
/* Check that we only have one argument present. */
init_rand_state (rs, false);
/* Unscramble the seed. */
- unscramble_seed (seed, (unsigned char *) rs->s, sizeof seed);
+ scramble_seed (seed, rs->s);
/* Then copy it back to the user variable. */
for (size_t i = 0; i < SZ ; i++)
memcpy (&(get->base_addr[(SZ - 1 - i) * GFC_DESCRIPTOR_STRIDE(get,0)]),
- seed + i * sizeof(GFC_UINTEGER_4),
+ (unsigned char*) seed + i * sizeof(GFC_UINTEGER_4),
sizeof(GFC_UINTEGER_4));
/* Finally copy the value of p after the seed. */
/* We copy the seed given by the user. */
for (size_t i = 0; i < SZ; i++)
- memcpy (seed + i * sizeof(GFC_UINTEGER_4),
+ memcpy ((unsigned char*) seed + i * sizeof(GFC_UINTEGER_4),
&(put->base_addr[(SZ - 1 - i) * GFC_DESCRIPTOR_STRIDE(put,0)]),
sizeof(GFC_UINTEGER_4));
/* We put it after scrambling the bytes, to paper around users who
provide seeds with quality only in the lower or upper part. */
- scramble_seed ((unsigned char *) master_state, seed, sizeof seed);
+ scramble_seed (master_state, seed);
njumps = 0;
master_init = true;
init_rand_state (rs, true);
rs->p = put->base_addr[SZ * GFC_DESCRIPTOR_STRIDE(put, 0)] & 15;
}
-
-
__gthread_mutex_unlock (&random_lock);
}
#undef SZ
void
random_seed_i8 (GFC_INTEGER_8 *size, gfc_array_i8 *put, gfc_array_i8 *get)
{
+ uint64_t seed[SZU64];
+
/* Check that we only have one argument present. */
if ((size ? 1 : 0) + (put ? 1 : 0) + (get ? 1 : 0) > 1)
runtime_error ("RANDOM_SEED should have at most one argument present.");
if (!rs->init)
init_rand_state (rs, false);
+ /* Unscramble the seed. */
+ scramble_seed (seed, rs->s);
+
/* This code now should do correct strides. */
for (size_t i = 0; i < SZ; i++)
- memcpy (&(get->base_addr[i * GFC_DESCRIPTOR_STRIDE(get,0)]), &rs->s[i],
+ memcpy (&(get->base_addr[i * GFC_DESCRIPTOR_STRIDE(get,0)]), &seed[i],
sizeof (GFC_UINTEGER_8));
get->base_addr[SZ * GFC_DESCRIPTOR_STRIDE(get, 0)] = rs->p;
/* This code now should do correct strides. */
for (size_t i = 0; i < SZ; i++)
- memcpy (&master_state[i], &(put->base_addr[i * GFC_DESCRIPTOR_STRIDE(put,0)]),
+ memcpy (&seed[i], &(put->base_addr[i * GFC_DESCRIPTOR_STRIDE(put,0)]),
sizeof (GFC_UINTEGER_8));
+ scramble_seed (master_state, seed);
njumps = 0;
master_init = true;
init_rand_state (rs, true);