1 /*
2  * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _PICO_RAND_H
8 #define _PICO_RAND_H
9 
10 #include "pico.h"
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 
16 /** \file pico/rand.h
17  *  \defgroup pico_rand pico_rand
18  *
19  * \brief Random Number Generator API
20  *
21  * This module generates random numbers at runtime utilizing a number of possible entropy
22  * sources and uses those sources to modify the state of a 128-bit 'Pseudo
23  * Random Number Generator' implemented in software.
24  *
25  * The random numbers (32 to 128 bit) to be supplied are read from the PRNG which is used
26  * to help provide a large number space.
27  *
28  * The following (multiple) sources of entropy are available (of varying quality), each enabled by a #define:
29  *
30  *  - The Ring Oscillator (ROSC) (\ref PICO_RAND_ENTROPY_SRC_ROSC == 1):
31  *    \ref PICO_RAND_ROSC_BIT_SAMPLE_COUNT bits are gathered from the ring oscillator "random bit" and mixed in each
32  *    time. This should not be used if the ROSC is off, or the processor is running from
33  *    the ROSC.
34  *    \note the maximum throughput of ROSC bit sampling is controlled by PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US which defaults
35  *    to 10us, i.e. 100,000 bits per second.
36  *  - Time (\ref PICO_RAND_ENTROPY_SRC_TIME == 1): The 64-bit microsecond timer is mixed in each time.
37  *  - Bus Performance Counter (\ref PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER == 1): One of the bus fabric's performance
38  *    counters is mixed in each time.
39  *
40  * \note All entropy sources are hashed before application to the PRNG state machine.
41  *
42  * The \em first time a random number is requested, the 128-bit PRNG state
43  * must be seeded. Multiple entropy sources are also available for the seeding operation:
44  *
45  *  - The Ring Oscillator (ROSC) (\ref PICO_RAND_SEED_ENTROPY_SRC_ROSC == 1):
46  *    64 bits are gathered from the ring oscillator "random bit" and mixed into the seed.
47  *  - Time (\ref PICO_RAND_SEED_ENTROPY_SRC_TIME == 1): The 64-bit microsecond timer is mixed into the seed.
48  *  - Board Identifier (PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID == 1): The board id via \ref pico_get_unique_board_id
49  *    is mixed into the seed.
50  *  - RAM hash (\ref PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH (\ref PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH): The hashed contents of a
51  *    subset of RAM are mixed in. Initial RAM contents are undefined on power up, so provide a reasonable source of entropy.
52  *    By default the last 1K of RAM (which usually contains the core 0 stack) is hashed, which may also provide for differences
53  *    after each warm reset.
54  *
55  * With default settings, the seed generation takes approximately 1 millisecond while
56  * subsequent random numbers generally take between 10 and 20 microseconds to generate.
57  *
58  * pico_rand methods may be safely called from either core or from an IRQ, but be careful in the latter case as
59  * the calls may block for a number of microseconds waiting on more entropy.
60  */
61 
62 // ---------------
63 // ENTROPY SOURCES
64 // ---------------
65 
66 // PICO_CONFIG: PICO_RAND_ENTROPY_SRC_ROSC, Enable/disable use of ROSC as an entropy source, type=bool, default=1 if no hardware TRNG, group=pico_rand
67 #ifndef PICO_RAND_ENTROPY_SRC_ROSC
68 #if !HAS_RP2350_TRNG
69 #define PICO_RAND_ENTROPY_SRC_ROSC 1
70 #endif
71 #endif
72 
73 // PICO_CONFIG: PICO_RAND_ENTROPY_SRC_TRNG, Enable/disable use of hardware TRNG as an entropy source, type=bool, default=1 if hardware TRNG is available, group=pico_rand
74 #ifndef PICO_RAND_ENTROPY_SRC_TRNG
75 #if HAS_RP2350_TRNG
76 #define PICO_RAND_ENTROPY_SRC_TRNG 1
77 #endif
78 #endif
79 
80 // PICO_CONFIG: PICO_RAND_ENTROPY_SRC_TIME, Enable/disable use of hardware timestamp as an entropy source, type=bool, default=1, group=pico_rand
81 #ifndef PICO_RAND_ENTROPY_SRC_TIME
82 #define PICO_RAND_ENTROPY_SRC_TIME 1
83 #endif
84 
85 // PICO_CONFIG: PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER, Enable/disable use of a bus performance counter as an entropy source, type=bool, default=1 if no hardware TRNG, group=pico_rand
86 #ifndef PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER
87 #if !HAS_RP2350_TRNG
88 #define PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER 1
89 #endif
90 #endif
91 
92 // --------------------
93 // SEED ENTROPY SOURCES
94 // --------------------
95 
96 // PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_ROSC, Enable/disable use of ROSC as an entropy source for the random seed, type=bool, default=PICO_RAND_ENTROPY_SRC_ROSC, group=pico_rand
97 #ifndef PICO_RAND_SEED_ENTROPY_SRC_ROSC
98 #define PICO_RAND_SEED_ENTROPY_SRC_ROSC PICO_RAND_ENTROPY_SRC_ROSC
99 #endif
100 
101 // PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_TRNG, Enable/disable use of hardware TRNG as an entropy source for the random seed, type=bool, default=PICO_RAND_ENTROPY_SRC_TRNG, group=pico_rand
102 #if !defined(PICO_RAND_SEED_ENTROPY_SRC_TRNG) && HAS_RP2350_TRNG
103 #define PICO_RAND_SEED_ENTROPY_SRC_TRNG PICO_RAND_ENTROPY_SRC_TRNG
104 #endif
105 
106 // PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_TIME, Enable/disable use of hardware timestamp as an entropy source for the random seed, type=bool, default=PICO_RAND_ENTROPY_SRC_TIME, group=pico_rand
107 #ifndef PICO_RAND_SEED_ENTROPY_SRC_TIME
108 #define PICO_RAND_SEED_ENTROPY_SRC_TIME PICO_RAND_ENTROPY_SRC_TIME
109 #endif
110 
111 // PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_BUS_PERF_COUNTER, Enable/disable use of a bus performance counter as an entropy source for the random seed, type=bool, default=PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER, group=pico_rand
112 #ifndef PICO_RAND_SEED_ENTROPY_SRC_BUS_PERF_COUNTER
113 #define PICO_RAND_SEED_ENTROPY_SRC_BUS_PERF_COUNTER PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER
114 #endif
115 
116 // PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_BOOT_RANDOM, Enable/disable use of the per boot random number as an entropy source for the random seed, type=bool, default=0 on RP2040 which has none, group=pico_rand
117 #ifndef PICO_RAND_SEED_ENTROPY_SRC_BOOT_RANDOM
118 #if !PICO_RP2040
119 #define PICO_RAND_SEED_ENTROPY_SRC_BOOT_RANDOM 1
120 #endif
121 #endif
122 
123 // PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID, Enable/disable use of board id as part of the random seed, type=bool, default=not PICO_RAND_SEED_ENTROPY_SRC_BOOT_RANDOM, group=pico_rand
124 #ifndef PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID
125 #define PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID (!PICO_RAND_SEED_ENTROPY_SRC_BOOT_RANDOM)
126 #endif
127 
128 // PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH, Enable/disable use of a RAM hash as an entropy source for the random seed, type=bool, default=1 if no hardware TRNG, group=pico_rand
129 #ifndef PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH
130 #if !HAS_RP2350_TRNG
131 #define PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH 1
132 #endif
133 #endif
134 
135 // ---------------------------------
136 // PICO_RAND_ENTROPY_SRC_ROSC CONFIG
137 // ---------------------------------
138 
139 // PICO_CONFIG: PICO_RAND_ROSC_BIT_SAMPLE_COUNT, Number of samples to take of the ROSC random bit per random number generation , min=1, max=64, default=1, group=pico_rand
140 #ifndef PICO_RAND_ROSC_BIT_SAMPLE_COUNT
141 #define PICO_RAND_ROSC_BIT_SAMPLE_COUNT 1
142 #endif
143 
144 // PICO_CONFIG: PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US, Define a default minimum time between sampling the ROSC random bit, min=5, max=20, default=10, group=pico_rand
145 #ifndef PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US
146 // (Arbitrary / tested) minimum time between sampling the ROSC random bit
147 #define PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US 10u
148 #endif
149 
150 // ---------------------------------------------
151 // PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER CONFIG
152 // ---------------------------------------------
153 
154 // PICO_CONFIG: PICO_RAND_BUS_PERF_COUNTER_INDEX, Bus performance counter index to use for sourcing entropy, min=0, max=3, default=Undefined meaning pick one that is not counting any valid event already, group=pico_rand
155 // this is deliberately undefined by default, meaning the code will pick that appears unused
156 #if 0 // make tooling checks happy
157 #define PICO_RAND_BUS_PERF_COUNTER_INDEX 0
158 #endif
159 
160 // PICO_CONFIG: PICO_RAND_BUS_PERF_COUNTER_EVENT, Bus performance counter event to use for sourcing entropy, default=arbiter_sram5_perf_event_access, group=pico_rand
161 #ifndef PICO_RAND_BUS_PERF_COUNTER_EVENT
162 #define PICO_RAND_BUS_PERF_COUNTER_EVENT arbiter_sram5_perf_event_access
163 #endif
164 
165 // ------------------------------------------
166 // PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH CONFIG
167 // ------------------------------------------
168 
169 // PICO_CONFIG: PICO_RAND_RAM_HASH_END, End of address in RAM (non-inclusive) to hash during pico_rand seed initialization, default=SRAM_END, group=pico_rand
170 #ifndef PICO_RAND_RAM_HASH_END
171 #define PICO_RAND_RAM_HASH_END     SRAM_END
172 #endif
173 // PICO_CONFIG: PICO_RAND_RAM_HASH_START, Start of address in RAM (inclusive) to hash during pico_rand seed initialization, default=PICO_RAND_RAM_HASH_END - 1024, group=pico_rand
174 #ifndef PICO_RAND_RAM_HASH_START
175 #define PICO_RAND_RAM_HASH_START   (PICO_RAND_RAM_HASH_END - 1024u)
176 #endif
177 
178 // We provide a maximum of 128 bits entropy in one go
179 typedef struct rng_128 {
180     uint64_t r[2];
181 } rng_128_t;
182 
183 /*! \brief Get 128-bit random number
184  *  \ingroup pico_rand
185  *
186  * This method may be safely called from either core or from an IRQ, but be careful in the latter case as
187  * the call may block for a number of microseconds waiting on more entropy.
188  *
189  * \param rand128 Pointer to storage to accept a 128-bit random number
190  */
191 void get_rand_128(rng_128_t *rand128);
192 
193 /*! \brief Get 64-bit random number
194  *  \ingroup pico_rand
195  *
196  * This method may be safely called from either core or from an IRQ, but be careful in the latter case as
197  * the call may block for a number of microseconds waiting on more entropy.
198  *
199  * \return 64-bit random number
200  */
201 uint64_t get_rand_64(void);
202 
203 /*! \brief Get 32-bit random number
204  *  \ingroup pico_rand
205  *
206  * This method may be safely called from either core or from an IRQ, but be careful in the latter case as
207  * the call may block for a number of microseconds waiting on more entropy.
208  *
209  * \return 32-bit random number
210  */
211 uint32_t get_rand_32(void);
212 
213 #ifdef __cplusplus
214 }
215 #endif
216 
217 #endif
218