random: OS 난수 채우기

OS 엔트로피로 버퍼를 채우고 부분 실패를 처리합니다.

Wave Foundation

API

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

size는 바이트 수이고 저장 공간은 호출자가 제공합니다. RandomFillResult에는 ok, written, error가 있습니다. 성공하면 written은 요청 길이입니다. 실패하면 written은 유효하게 채워진 접두사의 길이이며 나머지를 난수로 사용하지 않습니다.

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로 원인을 확인합니다. 난수 바이트를 문자로 그대로 출력하지 말고 필요하면 별도 인코딩을 사용하십시오.

요청이 잘못된 경우

0바이트 요청은 쓸 내용이 없으므로 성공합니다. 반면 양수 길이에 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으로 채운 뒤 성공으로 처리하면 안 됩니다.

난수를 정수 범위에 넣을 때도 분포를 고려해야 합니다. 균일한 u8 값에 % 10을 적용하면 05가 69보다 더 자주 나옵니다. 256이 10으로 나누어떨어지지 않기 때문입니다. 공정한 선택이 필요하다면 250~255를 버리고 다시 뽑은 뒤 나머지 연산을 적용하는 방식으로 편향을 제거할 수 있습니다.

난수 바이트의 저장 공간과 수명은 호출자가 관리합니다. 배열을 사용하면 배열 범위 안에서 처리하고, 동적 메모리를 사용하면 사용이 끝난 뒤 해제합니다. 반환 구조체가 버퍼를 대신 소유하지는 않습니다.