Use a XOR cipher instead of byte shuffling to protect against bad seeds.
libgfortran: 2016-08-19 Janne Blomqvist <jb@gcc.gnu.org> * intrinsics/random.c (xor_keys): New array with "secret" keys. (scramble_seed): XOR given seed with xor_keys array rather than shuffling bytes. (unscramble_seed): Remove function. (random_seed_i4): Use new scramble_seed. (random_seed_i8): Likewise. frontend: 2016-08-19 Janne Blomqvist <jb@gcc.gnu.org> * intrinsics.texi (RANDOM_NUMBER): Remove reference to init_random_seed in example. (RANDOM_SEED): Remove warning to not set all seed values to 0. From-SVN: r239613
This commit is contained in:
parent
91151a7334
commit
09309e09ec
4 changed files with 50 additions and 30 deletions
|
@ -1,3 +1,9 @@
|
|||
2016-08-19 Janne Blomqvist <jb@gcc.gnu.org>
|
||||
|
||||
* intrinsics.texi (RANDOM_NUMBER): Remove reference to
|
||||
init_random_seed in example.
|
||||
(RANDOM_SEED): Remove warning to not set all seed values to 0.
|
||||
|
||||
2016-08-18 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* error.c (gfc_diagnostic_starter): Update for change to
|
||||
|
|
|
@ -11155,7 +11155,6 @@ Subroutine
|
|||
@smallexample
|
||||
program test_random_number
|
||||
REAL :: r(5,5)
|
||||
CALL init_random_seed() ! see example of RANDOM_SEED
|
||||
CALL RANDOM_NUMBER(r)
|
||||
end program
|
||||
@end smallexample
|
||||
|
@ -11192,9 +11191,6 @@ alias any other stream in the system, where @var{N} is the number of
|
|||
threads that have used @code{RANDOM_NUMBER} so far during the program
|
||||
execution.
|
||||
|
||||
Note that setting any of the seed values to zero should be avoided as
|
||||
it can result in poor quality random numbers being generated.
|
||||
|
||||
@item @emph{Standard}:
|
||||
Fortran 95 and later
|
||||
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
2016-08-16 Janne Blomqvist <jb@gcc.gnu.org>
|
||||
2016-08-19 Janne Blomqvist <jb@gcc.gnu.org>
|
||||
|
||||
* intrinsics/random.c (xor_keys): New array with "secret" keys.
|
||||
(scramble_seed): XOR given seed with xor_keys array rather than
|
||||
shuffling bytes.
|
||||
(unscramble_seed): Remove function.
|
||||
(random_seed_i4): Use new scramble_seed.
|
||||
(random_seed_i8): Likewise.
|
||||
|
||||
2016-08-19 Janne Blomqvist <jb@gcc.gnu.org>
|
||||
|
||||
* intrinsics/random.c (master_init): New variable.
|
||||
(init_rand_state): Move below getosrandom (), maybe initialize
|
||||
|
|
|
@ -722,28 +722,33 @@ arandom_r16 (gfc_array_r16 *x)
|
|||
#endif
|
||||
|
||||
|
||||
/* Number of elements in master_state array. */
|
||||
#define SZU64 (sizeof (master_state) / sizeof (uint64_t))
|
||||
|
||||
|
||||
/* 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
|
||||
scramble_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 % 2) * (size / 2) + i / 2] = src[i];
|
||||
for (int i = 0; i < (int) SZU64; i++)
|
||||
dest[i] = src[i] ^ xor_keys[i];
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
unscramble_seed (unsigned char *dest, unsigned char *src, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
dest[i] = src[(i % 2) * (size / 2) + i / 2];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 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. */
|
||||
|
@ -751,7 +756,7 @@ unscramble_seed (unsigned char *dest, unsigned char *src, int size)
|
|||
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. */
|
||||
|
@ -778,12 +783,12 @@ random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get)
|
|||
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. */
|
||||
|
@ -814,13 +819,13 @@ random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get)
|
|||
|
||||
/* 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);
|
||||
|
@ -828,8 +833,6 @@ random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get)
|
|||
rs->p = put->base_addr[SZ * GFC_DESCRIPTOR_STRIDE(put, 0)] & 15;
|
||||
}
|
||||
|
||||
|
||||
|
||||
__gthread_mutex_unlock (&random_lock);
|
||||
}
|
||||
#undef SZ
|
||||
|
@ -840,6 +843,8 @@ iexport(random_seed_i4);
|
|||
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.");
|
||||
|
@ -864,9 +869,12 @@ random_seed_i8 (GFC_INTEGER_8 *size, gfc_array_i8 *put, gfc_array_i8 *get)
|
|||
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;
|
||||
|
@ -896,9 +904,10 @@ random_seed_i8 (GFC_INTEGER_8 *size, gfc_array_i8 *put, gfc_array_i8 *get)
|
|||
|
||||
/* 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);
|
||||
|
|
Loading…
Add table
Reference in a new issue