풀이 날짜: 2026-09-16 (사용자 확정). 익스플로잇 성공은 2026-09-16 사용자 확인에 따른다. 아래 실행 결과는 보존된 원본 기록이며 이번 감사에서 새로 실행한 결과가 아니다.
출력 합 0이 요구하는 조건
원본 chal.py의 결정적인 검사는 다음 식이다.
sum(r.getrandbits(32) for _ in range(396)) == 0
각 출력은 0 이상인 32비트 정수이므로 서로 상쇄될 수 없다. 따라서 합이 0이라는 조건은 첫 396개 출력 각각이 모두 0이라는 조건과 같다.
각 i에 대해 0 <= X_i < 2^32
Σ X_i = 0 ⇔ 모든 i에서 X_i = 0
단일한 우연한 합을 찾는 문제가 아니라 긴 초기 출력 구간을 만족시키는 상태와 정수 seed의 관계를 다루는 문제다.
내부 상태와 정수 seed를 구분한 분석
CONSTRUCTION은 Mersenne Twister의 tempering이 가역이라는 점을 이용해 출력 조건과 twist 결과 조건의 관계를 분석한다. 이어 CPython의 정수 시딩 과정이 어떤 상태를 만들 수 있는지 별도로 검토한다. 목표 상태를 상상하는 것만으로는 충분하지 않으며 그 상태가 실제 Random(int) 초기화에서 생겨야 한다.
모델의 산술은 32비트다. 무제한 정수 연산으로 계산한 식과 각 단계에서 절단하는 연산을 같은 것으로 취급하지 않는다. 문서는 반복된 초기화 조건을 축약한 뒤 마지막 초기화 갱신의 차이를 residual로 검사한다. 여기서 residual=0은 모델의 끝 조건이며, 런타임의 실제 출력 검증을 대체하지 않는다.
왜 이전 긴 seed는 최종 답이 아닌가
| 자료 | 의미 | 기본 입력 제한과 관계 |
|---|---|---|
| 이전 solve.py / 긴 seed | 과거 구성·비교 자료 | 6,011자리로 기본 4,300자리 한도를 넘음 |
| solve_short.py | 후속 독립 구성 구현 | 4,296자리 결과를 기록 |
| solver.py | 최종 서비스 제출 구현 | 같은 최종 구성에 대응 |
최신 결과는 14,271비트·446개 단어의 정수 seed다. 4,296 < 4,300이라는 입력 조건과 첫 396개 출력이 모두 0이라는 난수 조건을 동시에 만족해야 한다. 입력 제한을 늘려 긴 seed를 받게 한 실행을 기본 challenge 성공으로 대체하지 않는다.
검증을 독립적으로 나눈 이유
기존 감사는 초기화 모델, 축약된 식, 실제 CPython 상태·출력을 각각 대조했다. audit_reduction.py의 실행 추적은 검증 대상 모델의 초기화 함수를 그대로 호출하는 방식이 아니다. README에는 모델 30개와 축약 192개 사례를 CPython 3.10.12 및 3.14.3과 비교한 기록이 있다.
잘못된 경계값의 거절과 seed 0의 실패도 대조군으로 남아 있다. seed를 발견하기 위한 탐색과 작은 인증서에서 결과를 재구성하는 단계의 비용·의존성을 구분한다. 발견에 사용한 환경을 최종 구현의 필수 의존성으로 잘못 적지 않는다.
결과
사용자는 익스플로잇 성공을 확인했다. 최신 README와 short-construction은 CPython 3.14.3의 기본 설정·원본 challenge에서의 성공을 기록하며 공식 원격 결과는 확인되지 않았다. 이전 긴 seed와 실패 분석도 source에 보존했다. 이번에는 seed를 생성하거나 원본 프로그램을 실행하지 않았다.
근거 자료
sources/singlerand_astra/chal.pysources/singlerand_astra/README.mdsources/singlerand_astra/CONSTRUCTION.mdsources/singlerand_astra/LONG_SEED.mdsources/singlerand_astra/artifacts/short-construction.json
원본 문서·solver·검증 로그는 전달 staging에 보존되어 있다. 이 경로들은 provenance이며 CMS의 다운로드 첨부 링크가 아니다.