Разработчик ddustin, известный по работе над Core-Lightning, раскопал историю коммитов в прошивке Coldcard и выяснил, почему у биткоинеров начали пропадать средства. В коммите под названием «runs» сообщение состоит из пяти символов, а сам коммит меняет 1534 строки кода. Именно там отключили аппаратный генератор случайных чисел строкой #define MICROPY_HW_ENABLE_RNG (0). Это заставило прошивку вместо аппаратного RNG использовать слабый генератор Yasmarang. Рядом стоял комментарий: «We have our own version of this code».
Второй проблемный коммит назывался «x» — один символ, около 1000 строк изменений. Разработчик пытался переопределить функции pyb_rng_get_obj через свои файлы rng.h и rng.c. Но в stm32 rng.c уже есть определение этой переменной, так что компилятор должен был выдать ошибку duplicate symbol. Вместо того чтобы разобраться, разработчик отключил аппаратный RNG — это убрало конфликт, и код собрался. Но сработало это по неправильной причине: отключение просто выкинуло кусок кода с повторным определением.
Хуже всего то, что переопределённые функции вообще не используются при создании кошелька. В прошивке v4.0.0 Python-код вызывает random.bytes(32) внутри make_new_wallet(). Этот вызов идёт через rng_get, а тот из-за MICROPY_HW_ENABLE_RNG (0) возвращает значение из Yasmarang. Слабый генератор делает энтропию seed'а крайне низкой — вот и уязвимость.
ddustin настаивает: нельзя выпускать код, который не понимаешь. Никаких оправданий. MicroPython создаёт иллюзию, что для embedded-разработки не нужно понимать C и CPU, но эта катастрофа — прямой результат такой веры. Нужно документировать изменения, проверять, что они делают именно то, что задумано, и не глушить ошибки компилятора, а слушать их. Особенно когда речь идёт о безопасности биткоин-кошельков.