1 /*
2  * Copyright (c) 2013-2015 Wind River Systems, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Non-random number generator based on system timer
10  *
11  * This module provides a non-random implementation of sys_rand32_get(), which
12  * is not meant to be used in a final product as a truly random number
13  * generator. It was provided to allow testing on a platform that does not (yet)
14  * provide a random number generator.
15  */
16 
17 #include <zephyr/random/random.h>
18 #include <zephyr/drivers/timer/system_timer.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/spinlock.h>
21 #include <string.h>
22 
23 #if defined(__GNUC__)
24 
25 static struct k_spinlock rand32_lock;
26 
27 /**
28  * @brief Get a 32 bit random number
29  *
30  * This pseudo-random number generator returns values that are based off the
31  * target's clock counter, which means that successive calls will return
32  * different values.
33  *
34  * @return a 32-bit number
35  */
z_impl_sys_rand32_get(void)36 uint32_t z_impl_sys_rand32_get(void)
37 {
38 	/* initial seed value */
39 	static uint64_t state = (uint64_t)CONFIG_TIMER_RANDOM_INITIAL_STATE;
40 	k_spinlock_key_t key = k_spin_lock(&rand32_lock);
41 
42 	state = state + k_cycle_get_32();
43 	state = state * 2862933555777941757ULL + 3037000493ULL;
44 	uint32_t val = (uint32_t)(state >> 32);
45 
46 	k_spin_unlock(&rand32_lock, key);
47 	return val;
48 }
49 
50 /**
51  * @brief Fill destination buffer with random numbers
52  *
53  * The pseudo-random number generator returns values that are based off the
54  * target's clock counter, which means that successive calls will return
55  * different values.
56  *
57  * @param dst destination buffer to fill
58  * @param outlen size of destination buffer to fill
59  */
z_impl_sys_rand_get(void * dst,size_t outlen)60 void z_impl_sys_rand_get(void *dst, size_t outlen)
61 {
62 	uint8_t *udst = dst;
63 	uint32_t blocksize;
64 	uint32_t ret;
65 
66 	while (outlen) {
67 		ret = sys_rand32_get();
68 		blocksize = MIN(outlen, sizeof(ret));
69 		(void)memcpy((void *)udst, &ret, blocksize);
70 		udst += blocksize;
71 		outlen -= blocksize;
72 	}
73 }
74 #endif /* __GNUC__ */
75