random: заполнение буферов случайностью ОС.

OS Заполнить буфер энтропией и обработать частичные сбои.

Wave Foundation

API

std::random::fill
random_available() -> bool
random_fill(buffer: ptr<u8>, size: i64) -> RandomFillResult

размер — это количество байтов, а вызывающая сторона предоставляет хранилище. RandomFillResult содержит ОК, написано и ошибка. В случае успеха записанное значение будет равно запрошенной длине. В случае сбоя запись идентифицирует действительный заполненный префикс; не используйте оставшиеся байты как случайные данные.

random_available сообщает, поддерживается ли функция OS случайных чисел. Успех отдельного запроса проверяется по результатам random_fill. Использует только энтропию OS и не использует возврат к значению времени или слабый PRNG в случае сбоя. size=0 будет успешным, даже если он будет передан вместе с null. null — ошибка для отрицательной или положительной длины.

Запуск примера

import("std::random::fill")::{
    RandomFillResult, random_fill
};

fun main() -> i32 {
    var bytes: array<u8, 16>;
    var result: RandomFillResult = random_fill(&bytes[0], 16);
    if (!result.ok) {
        println("random error={}", result.error);
        return 1;
    }

    println("filled={}", result.written);
    return 0;
}

Результат выполнения:

filled=16

Сохраните его как main.wave и запустите. Содержимое байтов каждый раз разное, поэтому конкретного значения не ожидается. Если это не помогло, проверьте причину с помощью result.error. Вместо того, чтобы выводить случайные байты буквально, при необходимости используйте отдельную кодировку.

Если ваш запрос неверен

Запрос с нулевым байтом выполняется успешно, поскольку ничего не нужно записывать. Передача null с положительной длиной не удалась, поскольку буфер назначения отсутствует. Следующая программа сравнивает эти случаи без выделения памяти.

import("std::random::fill")::{
    RandomFillResult,
    random_fill
};

fun main() -> i32 {
    var empty: RandomFillResult = random_fill(null, 0);

    if (!empty.ok || empty.written != 0) {
        return 1;
    }

    println("empty request succeeded");

    var invalid: RandomFillResult = random_fill(null, 16);

    if (invalid.ok) {
        return 2;
    }

    println("missing buffer rejected");
    return 0;
}

Результат выполнения:

empty request succeeded
missing buffer rejected

Обработка частично заполненных буферов

Если были запрошены 16 байтов, но произошла ошибка и возвращается written=8, заполняются только первые 8 байтов. Если задача состоит в создании 16-байтового идентификатора, это не успешный идентификатор, поэтому мы отбрасываем весь результат и сообщаем об ошибке. Не следует заполнять оставшиеся 8 байтов 0 и затем считать это успешным.

Сопоставление случайных байтов с целочисленным диапазоном требует осторожности. Применение % 10 к равномерно распределенным значениям u8 делает 0–5 более вероятным, чем 6–9, поскольку 256 не делится на 10. Чтобы устранить это смещение, отклоните значения 250–255, нарисуйте заново и примените операцию остатка только к принятым значениям.

Хранением и временем жизни случайных байтов управляет вызывающая сторона. При использовании массива он обрабатывается в пределах массива, а при использовании динамической памяти освобождается после использования. Вместо этого возвращаемая структура не владеет буфером.