Зачем нужен TRNG?
В мире встраиваемых систем безопасность и уникальность данных часто зависят от качества случайных чисел. Будь то генерация криптографических ключей, создание уникальных идентификаторов для устройств в сети (MAC-адреса) или просто рандомизация поведения игры — везде нужен источник энтропии
Существует два подхода к генерации случайных чисел:
- PRNG (Pseudo-Random Number Generator) — генератор псевдослучайных чисел. Это математический алгоритм. Он детерминирован: зная начальное число (seed) и алгоритм, можно предсказать всю последовательность
- TRNG (True Random Number Generator) — генератор истинно случайных чисел. Он использует физические процессы (шумы) для создания непредсказуемой последовательности
В то время как многие современные микроконтроллеры (особенно из серий STM32F2/F4/F7, ESP32) имеют встроенный TRNG, бюджетные модели часто его лишены
Создаем свой TRNG
Самый распространенный DIY-метод получения случайности в аналоговом мире — использование лавинного шума (Avalanche Noise)
Как это работает?
- Обратносмещенный p-n переход: Если взять полупроводниковый диод (или стабилитрон) и подключить его в обратном направлении, он не будет проводить ток до достижения определенного напряжения пробоя
- Режим пробоя: Когда напряжение приближается к напряжению пробоя, электроны в области обеднения начинают лавинообразно размножаться под действием сильного электрического поля
- Шум: Этот процесс не является гладким. Из-за квантовых эффектов и неоднородностей кристалла ток через переход флуктуирует с очень высокой частотой. Эти флуктуации и есть "белый шум"
Мы можем оцифровать этот шум с помощью АЦП микроконтроллера. Младшие биты АЦП будут постоянно меняться хаотично. Если отбросить старшие разряды (которые могут быть смещены напряжением питания) и взять только, например, 1-2 младших бита, мы получим сырой поток случайных битов
Схема подключения к CH32V003:
Питание 3.3В от микроконтроллера
Резистор - 10 кОм
Стабилитрон 3.3В катодом к питанию через резистор, анодом на землю (GND)
Точка соединения резистора и катода стабилитрона подключается к аналоговому пину PA2
Программирование на CH32V003 в MounRiver Studio
Будем использовать библиотеку ch32fun
Включим и настроим UART
Файл funconfig.h
#ifndef _FUNCONFIG_H
#define _FUNCONFIG_H
#define CH32V003 1
#define FUNCONF_USE_DEBUGPRINTF 0
#define FUNCONF_USE_UARTPRINTF 1
#define FUNCONF_UART_PRINTF_BAUD 115200
#endif
Файл main.c
Значения по умолчанию
#define NUM_SAMPLES 64 //количество выборок
#define SAMPLE_DELAY_US 10 //промежуток между выборками
Генерация случайно распределённого байта
Используем funAnalogRead для чтения значения c PA2
uint8_t generateRandomByte() {
uint8_t byte = 0;
for(uint8_t i = 0; i < 8; ++i) { // Создаем 8-разрядный байт
uint16_t sum = 0;
// Берём среднее из N выборок для каждого бита
for(uint8_t j = 0; j < NUM_SAMPLES; ++j) {
sum += funAnalogRead(ANALOG_2) & 0xFF;
Delay_Us(SAMPLE_DELAY_US);
}
// Преобразуем сумму выборок в случайный бит с помощью сдвигов
_Bool bit = (sum >> 1) & 1;
byte |= (bit << i); // Устанавливаем соответствующий бит
}
return byte;
}
Сборка случайного целого числа из отдельных байтов
unsigned long assembleRandomNumber(int num_bytes) {
unsigned long result = 0;
for(int i = 0; i < num_bytes; ++i) {
uint8_t rnd_byte = generateRandomByte();
result = (result << 8) | rnd_byte;
}
return result;
}
В основном коде вызываем функцию assembleRandomNumber с параметром(8) и получаем случайные числа в диапазоне от 0 до 255
Полный код здесь
Значения выводим в терминал через UART
Есть проверка на нули. Если часто появляется 0, выходит сообщение ERROR. Что говорит о неправильной работе генератора
Теперь можно через переходник USB-TTL (TX -> RX) подключить полученное устройство к компьютеру
И считывать случайные числа на компьютере
Статья на эту тему
Написал пару примеров для теста
Пример 1. Считываем отрезками по 5 чисел. Первые 3 числа цвет в RGB. Последние два координаты. Рисуем случайный рисунок на полотне 255х255
Пример 2. Каждое число — это направление движения: влево, вправо, вверх, вниз. Делим 255 на четыре части. Попадание числа в заданный промежуток дает направление. Движение начинается с центра рисунка
Каждый может сам оценить распределение чисел
Теперь о том, действительно ли это случайные числа. Схема со стабилитроном, работающим в режиме пробоя, генерирует шум, который может быть источником энтропии. АЦП считывает этот шум, и если шум достаточно случайный, то на выходе могут получаться случайные значения. Однако качество энтропии зависит от многих факторов: уровня шума, характеристик стабилитрона, помех в цепи АЦП, скорости семплирования. Функция использует усреднение множества выборок для получения одного бита, что может улучшить случайность, но также снижает скорость генерации. Такой генератор подходит для каких-то простых задач. Для криптографически стойких приложений всегда рекомендуется использовать проверенные схемы с дополнительной фильтрацией и статистической проверкой полученных данных (тесты NIST STS)
Реализую этот генератор в каком-нибудь проекте. Подписывайся, чтобы не пропустить