Random 함수는 진짜 "Random"할까?

rivermoon·2025년 4월 23일
post-thumbnail

Introduction

얼마 전 랜덤 이벤트 기능을 개발하다 문득 이런 생각이 들었어요.

"이게 진짜 무작위일까?"

컴퓨터가 숫자를 만들어내는 방식은 결국 사람이 정의한 수식과 알고리즘인데… 정말 예측 불가능한 걸까?

이번 아티클에서는 Random의 작동 원리, 진짜 무작위(Random)와 의사 무작위(Pseudo-Random)의 차이, Kotlin/Java의 Random은 어디에 속하는지, 그리고 보안적으로 안전한 랜덤 생성 방식까지 다뤄보겠습니다.


진짜 Random과 가짜 Random?

구분설명예시
진짜 무작위 (True Random)자연 현상 기반, 예측 불가라디오 노이즈, 원자 붕괴, 마우스 이동 패턴
의사 무작위 (Pseudo Random)알고리즘 기반, 예측 가능Kotlin/Java Random, Python random()

핵심 차이

True Random: 외부 물리적 현상을 기반으로 함 (하드웨어 필요)
Pseudo Random: 특정 시드(seed) 값으로 시작되는 알고리즘 → 재현 가능


의사 난수의 수학적 원리

의사 난수 생성기는 보통 수학 공식을 기반으로 난수를 생성합니다.
그중 가장 유명한 방식은 선형 합동 생성기(Linear Congruential Generator, LCG)입니다.

선형 합동 생성기 공식

Xₙ₊₁ = (aXₙ + c) mod m
  • Xₙ: 현재 난수
  • a: 계수 (multiplier)
  • c: 상수 (increment)
  • m: 모듈로 값 (modulus)
  • 시드(Seed): X₀ 초기값 (기준점)

예시)
a = 5, c = 3, m = 16, X₀ = 7 → X₁ = (5×7 + 3) mod 16 = 38 mod 16 = 6
시드 값을 같게 하면, 생성되는 모든 난수의 시퀀스가 완전히 동일합니다.

랜덤숫자 = (??? * a + b) / c

많은 난수 생성기들은 위와 비슷한 수식을 기반으로 반복 계산을 수행해 난수를 생성합니다.
일반적으로는 곱셈 + 덧셈 → 모듈로 연산을 통해 0 ~ m 사이의 값을 순환시키는 방식입니다.
그래서 결국 무한하지 않고, 어느 시점에서는 패턴이 반복됩니다. (이를 주기(Period)라고 합니다)


Kotlin의 Random은..?

Kotlin의 기본 Random()은 내부적으로 Java의 java.util.Random 또는 kotlin.random.Random.Default를 사용합니다.

val random = Random(42)
println(random.nextInt()) // 항상 동일한 값 출력

이 방식은 의사 무작위(Pseudo-Random) 생성기고, 고정된 시드값이 주어지면 항상 동일한 결과를 반환하죠.

시드(Seed)란?

시드는 랜덤 함수가 시작되는 "초기값"으로, 같은 시드 → 같은 난수열을 보장합니다.
여기서 바로 "Random이 조작 가능하다"는 의미의 본질이 되죠.


왜 의사 무작위(Pseudo)가 필요한가?

  1. 재현성 확보: 테스트 시 동일한 결과 필요할 때
  2. 성능 우위: 하드웨어 없이도 빠르게 생성 가능
  3. 메모리 효율: 알고리즘만으로 무한한 숫자 시뮬레이션 가능

BUT.. 중요한 건…
"보안에 쓰기에는 부적절합니다."


보안에서의 Random은 다르다

암호, 토큰, 인증 코드 등 보안 목적의 난수는 예측이 불가능해야 합니다.
이 때는 SecureRandom 또는 OS 레벨의 무작위 API를 사용합니다.


Kotlin에서 SecureRandom 사용하기

val secureRandom = SecureRandom()
val token = ByteArray(16)
secureRandom.nextBytes(token)
println(token.joinToString())
  • 내부적으로 Linux의 /dev/urandom, Windows의 CSPRNG API 등을 통해 값을 생성합니다.
  • CPU or OS에서 수집한 엔트로피(불확실성)를 기반으로 작동합니다.

비교

항목RandomSecureRandom
타입Pseudo RandomCryptographic Secure Random
시드 변경가능불가 / 내부에서 자동 관리됨
예측 가능성있음없음
보안용도 적합성

마무리

Random()은 일상적인 개발에는 충분히 훌륭한 도구입니다.
하지만 진짜 무작위처럼 완전히 예측 불가능한 값은 아니라는 점을 기억해야 해요.

게임의 주사위, UI 애니메이션, 테스트 데이터 → Random()
로그인 인증번호, 비밀번호 토큰, 세션 키 → SecureRandom() 또는 UUID.randomUUID()

이제부터는 "진짜 랜덤인가?"라는 질문이 생겼을 때,
그건 '무엇을 위한 랜덤'인지 먼저 생각해보면 좋을 것 같습니다 ㅎ

profile
Android Developer

0개의 댓글