Найти в Дзене
Паяльник и код

Аппаратный генератор случайных чисел (TRNG) на микроконтроллере CH32V003: Используем шум стабилитрона

Зачем нужен TRNG? В мире встраиваемых систем безопасность и уникальность данных часто зависят от качества случайных чисел. Будь то генерация криптографических ключей, создание уникальных идентификаторов для устройств в сети (MAC-адреса) или просто рандомизация поведения игры — везде нужен источник энтропии Существует два подхода к генерации случайных чисел: В то время как многие современные микроконтроллеры (особенно из серий STM32F2/F4/F7, ESP32) имеют встроенный TRNG, бюджетные модели часто его лишены Создаем свой TRNG Самый распространенный DIY-метод получения случайности в аналоговом мире — использование лавинного шума (Avalanche Noise) Как это работает? Мы можем оцифровать этот шум с помощью АЦП микроконтроллера. Младшие биты АЦП будут постоянно меняться хаотично. Если отбросить старшие разряды (которые могут быть смещены напряжением питания) и взять только, например, 1-2 младших бита, мы получим сырой поток случайных битов Схема подключения к CH32V003: Питание 3.3В от микроконтро

Зачем нужен TRNG?

В мире встраиваемых систем безопасность и уникальность данных часто зависят от качества случайных чисел. Будь то генерация криптографических ключей, создание уникальных идентификаторов для устройств в сети (MAC-адреса) или просто рандомизация поведения игры — везде нужен источник энтропии

Существует два подхода к генерации случайных чисел:

  1. PRNG (Pseudo-Random Number Generator) — генератор псевдослучайных чисел. Это математический алгоритм. Он детерминирован: зная начальное число (seed) и алгоритм, можно предсказать всю последовательность
  2. TRNG (True Random Number Generator) — генератор истинно случайных чисел. Он использует физические процессы (шумы) для создания непредсказуемой последовательности

В то время как многие современные микроконтроллеры (особенно из серий STM32F2/F4/F7, ESP32) имеют встроенный TRNG, бюджетные модели часто его лишены

Создаем свой TRNG

Самый распространенный DIY-метод получения случайности в аналоговом мире — использование лавинного шума (Avalanche Noise)

Как это работает?

  • Обратносмещенный p-n переход: Если взять полупроводниковый диод (или стабилитрон) и подключить его в обратном направлении, он не будет проводить ток до достижения определенного напряжения пробоя
  • Режим пробоя: Когда напряжение приближается к напряжению пробоя, электроны в области обеднения начинают лавинообразно размножаться под действием сильного электрического поля
  • Шум: Этот процесс не является гладким. Из-за квантовых эффектов и неоднородностей кристалла ток через переход флуктуирует с очень высокой частотой. Эти флуктуации и есть "белый шум"

Мы можем оцифровать этот шум с помощью АЦП микроконтроллера. Младшие биты АЦП будут постоянно меняться хаотично. Если отбросить старшие разряды (которые могут быть смещены напряжением питания) и взять только, например, 1-2 младших бита, мы получим сырой поток случайных битов

-2

Схема подключения к CH32V003:

Питание 3.3В от микроконтроллера
Резистор - 10 кОм
Стабилитрон 3.3В катодом к питанию через резистор, анодом на землю (GND)
Точка соединения резистора и катода стабилитрона подключается к аналоговому пину PA2

-3

Программирование на 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) подключить полученное устройство к компьютеру

-4

И считывать случайные числа на компьютере

Статья на эту тему

Написал пару примеров для теста

Пример 1. Считываем отрезками по 5 чисел. Первые 3 числа цвет в RGB. Последние два координаты. Рисуем случайный рисунок на полотне 255х255

65 тыс случайных чисел
65 тыс случайных чисел
145 тыс  случайных чисел
145 тыс случайных чисел

Пример 2. Каждое число — это направление движения: влево, вправо, вверх, вниз. Делим 255 на четыре части. Попадание числа в заданный промежуток дает направление. Движение начинается с центра рисунка

127 тыс чисел
127 тыс чисел
Второй запуск  128 тыс чисел
Второй запуск 128 тыс чисел

Каждый может сам оценить распределение чисел

Теперь о том, действительно ли это случайные числа. Схема со стабилитроном, работающим в режиме пробоя, генерирует шум, который может быть источником энтропии. АЦП считывает этот шум, и если шум достаточно случайный, то на выходе могут получаться случайные значения. Однако качество энтропии зависит от многих факторов: уровня шума, характеристик стабилитрона, помех в цепи АЦП, скорости семплирования. Функция использует усреднение множества выборок для получения одного бита, что может улучшить случайность, но также снижает скорость генерации. Такой генератор подходит для каких-то простых задач. Для криптографически стойких приложений всегда рекомендуется использовать проверенные схемы с дополнительной фильтрацией и статистической проверкой полученных данных (тесты NIST STS)

Реализую этот генератор в каком-нибудь проекте. Подписывайся, чтобы не пропустить