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