|
| 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 | + * 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, group=pico_rand |
| 67 | +#ifndef PICO_RAND_ENTROPY_SRC_ROSC |
| 68 | +#define PICO_RAND_ENTROPY_SRC_ROSC 1 |
| 69 | +#endif |
| 70 | + |
| 71 | +// PICO_CONFIG: PICO_RAND_ENTROPY_SRC_TIME, Enable/disable use of hardware timestamp as an entropy source, type=bool, default=1, group=pico_rand |
| 72 | +#ifndef PICO_RAND_ENTROPY_SRC_TIME |
| 73 | +#define PICO_RAND_ENTROPY_SRC_TIME 1 |
| 74 | +#endif |
| 75 | + |
| 76 | +// 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, group=pico_rand |
| 77 | +#ifndef PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER |
| 78 | +#define PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER 1 |
| 79 | +#endif |
| 80 | + |
| 81 | +// -------------------- |
| 82 | +// SEED ENTROPY SOURCES |
| 83 | +// -------------------- |
| 84 | + |
| 85 | +// PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_ROSC, Enable/disable use of ROSC as an entropy source for the random seed, type=bool, default=1, group=pico_rand |
| 86 | +#ifndef PICO_RAND_SEED_ENTROPY_SRC_ROSC |
| 87 | +#define PICO_RAND_SEED_ENTROPY_SRC_ROSC PICO_RAND_ENTROPY_SRC_ROSC |
| 88 | +#endif |
| 89 | + |
| 90 | +// 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=1, group=pico_rand |
| 91 | +#ifndef PICO_RAND_SEED_ENTROPY_SRC_TIME |
| 92 | +#define PICO_RAND_SEED_ENTROPY_SRC_TIME PICO_RAND_ENTROPY_SRC_TIME |
| 93 | +#endif |
| 94 | + |
| 95 | +// PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID, Enable/disable use of board id as part of the random seed, type=bool, default=1, group=pico_rand |
| 96 | +#ifndef PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID |
| 97 | +#define PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID 0 |
| 98 | +#endif |
| 99 | + |
| 100 | +// 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, group=pico_rand |
| 101 | +#ifndef PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH |
| 102 | +#define PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH 1 |
| 103 | +#endif |
| 104 | + |
| 105 | +// --------------------------------- |
| 106 | +// PICO_RAND_ENTROPY_SRC_ROSC CONFIG |
| 107 | +// --------------------------------- |
| 108 | + |
| 109 | +// 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 |
| 110 | +#ifndef PICO_RAND_ROSC_BIT_SAMPLE_COUNT |
| 111 | +#define PICO_RAND_ROSC_BIT_SAMPLE_COUNT 1 |
| 112 | +#endif |
| 113 | + |
| 114 | +// 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 |
| 115 | +#ifndef PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US |
| 116 | +// (Arbitrary / tested) minimum time between sampling the ROSC random bit |
| 117 | +#define PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US 10u |
| 118 | +#endif |
| 119 | + |
| 120 | +// --------------------------------------------- |
| 121 | +// PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER CONFIG |
| 122 | +// --------------------------------------------- |
| 123 | + |
| 124 | +// PICO_CONFIG: PICO_RAND_BUS_PERF_COUNTER_INDEX, Bus performance counter index to use for sourcing entropy, min=0, max=3, group=pico_rand |
| 125 | +// this is deliberately undefined by default, meaning the code will pick that appears unused |
| 126 | +//#define PICO_RAND_BUS_PERF_COUNTER_INDEX 0 |
| 127 | + |
| 128 | +// 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 |
| 129 | +#ifndef PICO_RAND_BUS_PERF_COUNTER_EVENT |
| 130 | +#define PICO_RAND_BUS_PERF_COUNTER_EVENT arbiter_sram5_perf_event_access |
| 131 | +#endif |
| 132 | + |
| 133 | +// ------------------------------------------ |
| 134 | +// PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH CONFIG |
| 135 | +// ------------------------------------------ |
| 136 | + |
| 137 | +// 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 |
| 138 | +#ifndef PICO_RAND_RAM_HASH_END |
| 139 | +#define PICO_RAND_RAM_HASH_END SRAM_END |
| 140 | +#endif |
| 141 | +// 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 |
| 142 | +#ifndef PICO_RAND_RAM_HASH_START |
| 143 | +#define PICO_RAND_RAM_HASH_START (PICO_RAND_RAM_HASH_END - 1024u) |
| 144 | +#endif |
| 145 | + |
| 146 | +// We provide a maximum of 128 bits entropy in one go |
| 147 | +typedef struct rng_128 { |
| 148 | + uint64_t r[2]; |
| 149 | +} rng_128_t; |
| 150 | + |
| 151 | +/*! \brief Get 128-bit random number |
| 152 | + * \ingroup pico_rand |
| 153 | + * |
| 154 | + * This method may be safely called from either core or from an IRQ, but be careful in the latter case as |
| 155 | + * the call may block for a number of microseconds waiting on more entropy. |
| 156 | + * |
| 157 | + * \param rand128 Pointer to storage to accept a 128-bit random number |
| 158 | + */ |
| 159 | +void get_rand_128(rng_128_t *rand128); |
| 160 | + |
| 161 | +/*! \brief Get 64-bit random number |
| 162 | + * \ingroup pico_rand |
| 163 | + * |
| 164 | + * This method may be safely called from either core or from an IRQ, but be careful in the latter case as |
| 165 | + * the call may block for a number of microseconds waiting on more entropy. |
| 166 | + * |
| 167 | + * \return 64-bit random number |
| 168 | + */ |
| 169 | +uint64_t get_rand_64(void); |
| 170 | + |
| 171 | +/*! \brief Get 32-bit random number |
| 172 | + * \ingroup pico_rand |
| 173 | + * |
| 174 | + * This method may be safely called from either core or from an IRQ, but be careful in the latter case as |
| 175 | + * the call may block for a number of microseconds waiting on more entropy. |
| 176 | + * |
| 177 | + * \return 32-bit random number |
| 178 | + */ |
| 179 | +uint32_t get_rand_32(void); |
| 180 | + |
| 181 | +#ifdef __cplusplus |
| 182 | +} |
| 183 | +#endif |
| 184 | + |
| 185 | +#endif |
0 commit comments