Jane Street의 Neural Network 리버스 엔지니어링: SGD가 아닌 SAT Solver를 꺼낸 이유


“이 모델은 학습된 게 아닙니다.”

보통 우리는 Neural Network를 블랙박스로 취급합니다. 데이터 셋을 붓고, 아키텍처를 정하고, SGD(Stochastic Gradient Descent)가 알아서 최적의 가중치(Weight)를 찾아주길 기도하죠. 그런데 만약 누군가가 수작업으로 뉴럴넷의 가중치를 하나하나 깎아서 코딩했다면 어떨까요?

최근 Jane Street에서 공개한 “Can you reverse engineer our neural network?”라는 퍼즐이 엔지니어링 커뮤니티를 강타했습니다. 이 글은 단순한 퍼즐 풀이가 아닙니다. 이 과정에서 드러난 Mechanistic Interpretability(메커니즘 해석 가능성) 의 극한과, 이를 둘러싼 엔지니어들의 철학적 논쟁까지 깊게 파고들어 보겠습니다.

솔직히 말해서, 처음 이 문제를 봤을 때 저는 “그냥 Adversarial Attack 기법 좀 쓰면 뚫리겠네”라고 생각했습니다. 하지만 그건 제 오산이었습니다.


1. 이상한 텐서들의 무덤

문제는 간단합니다. model.pt 파일이 주어지고, 이 모델이 0이 아닌 값을 뱉어내게 하는 입력을 찾는 것입니다. 대부분의 입력에 대해 이 모델은 침묵(0)을 지킵니다.

일반적인 딥러닝 엔지니어라면 Input Gradient를 구해서 Backpropagation으로 입력을 최적화하려 했을 겁니다. 하지만 이 모델을 열어본 순간, 그 방법이 통하지 않을 거란 걸 직감하게 됩니다.

import torch
import plotly.express as px
model = torch.load('./model.pt')
linears = [x for x in model if isinstance(x, torch.nn.Linear)]
px.imshow(linears[-1].weight.detach())

마지막 레이어의 가중치를 시각화해보면 충격적인 사실이 드러납니다. 모든 가중치가 정수(Integer) 입니다. 노이즈가 전혀 없는, 완벽하게 정제된 값들. 이건 학습된 게 아니라 설계된 회로(Circuit) 라는 뜻입니다.

2. 뉴럴넷을 가장한 컴파일된 프로그램

문제를 푼 ‘Alex’라는 대학생의 접근 방식이 매우 인상적입니다. 그는 마지막 레이어가 3개의 섹션으로 나뉘어 있고, bias가 v, v+1, v+2 형태로 증가하는 패턴을 발견했습니다. 이건 전형적인 Equality Check 로직입니다.

  • ReLU 트릭: ReLU(x) + ReLU(-x) 등을 조합하면 논리 게이트를 만들 수 있습니다.
  • 이 모델은 입력값 v와 내부의 어떤 타겟값 x가 같은지 비교하는 거대한 비교 연산자였던 겁니다.

여기서부터 이 문제는 머신러닝 문제가 아니라 리버스 엔지니어링(Reverse Engineering) 문제가 됩니다. Alex는 여기서 멈추지 않고, 이 모델을 Integer Linear Program(정수 선형 계획법) 으로 변환해서 Solver에 태우는 시도를 합니다.

“이거 그냥 Z3 같은 Solver에 넣으면 풀리는 거 아냐?”

저도 비슷한 생각을 했을 겁니다. 하지만 200만 개의 노드를 가진 DAG(Directed Acyclic Graph)를 최적화하는 건 Solver에게도 지옥입니다. Alex는 Identity 레이어들을 압축하고 노드를 병합하여 변수를 75,000개까지 줄였지만, 여전히 Solver는 답을 내놓지 못했습니다.

3. 결정적 단서: MD5 해시의 주기성

Solver가 실패했다는 건, 이 내부 로직이 비가역적(Irreversible) 이라는 강력한 신호입니다. 비가역적인 함수? 바로 Hash Function 입니다.

레이어의 크기(Width)를 플로팅해보니 48의 주기를 가진 32개의 블록이 반복되는 패턴이 발견되었습니다. ChatGPT에게 “32개 블록을 사용하는 해시 함수가 뭐지?”라고 물어보니 답이 나옵니다. 바로 MD5 입니다.

결국 이 뉴럴넷은 MD5 해시 연산을 수행하는 하드코딩된 회로 였던 것입니다. 모델의 마지막 레이어 바이어스에 박혀있던 값은 특정 문자열의 MD5 해시값이었고요. 즉, 우리는 MD를 역산해야 하는 상황에 놓인 겁니다. (MD5가 뚫렸다곤 하지만, SAT Solver로 깡으로 뚫는 건 다른 차원의 문제입니다.)

4. 버그조차 수작업이다

가장 소름 돋았던 부분은 Alex가 발견한 버그입니다. 입력 길이가 32바이트를 넘어가면 모델이 오동작을 일으켰습니다. 원인을 파헤쳐보니, 입력 길이를 리틀 엔디안(Little-endian)으로 인코딩하는 초기 레이어의 회로가 길이가 256비트 이상일 때 비트 연산을 잘못 처리 하도록 설계되어 있었습니다.

Jane Street 측은 이게 의도한 버그가 아니라고 했습니다. 즉, 누군가가 이 거대한 뉴럴넷을 설계하면서 Parallel Carry Adder(병렬 캐리 가산기) 를 20여 개의 레이어로 직접 구현하다가 실수를 했다는 겁니다.

이 지점에서 저는 전율을 느꼈습니다. 요즘 우리는 import torch.nn as nn 한 줄로 수백만 파라미터를 만듭니다. 하지만 이 퍼즐의 출제자는 논리 게이트 수준에서 뉴럴넷을 깎았습니다. 이건 잃어버린 장인 정신(Craftsmanship)이나 다름없습니다.

5. 결말: 결국은 Brute Force

결국 이 문제의 해답은 기술적인 해킹이 아니라, 힌트를 조합한 Dictionary Attack 이었습니다. 정답은 두 개의 영단어 조합이었죠. 허무한가요? 하지만 보안의 세계에서 엔드게임은 언제나 가장 약한 고리(Weakest Link)를 찾는 것입니다.


Hacker News의 논쟁: 재능의 낭비인가?

이 글이 Hacker News에 올라오자마자, 댓글창은 기술적 분석을 넘어선 격렬한 논쟁으로 불타올랐습니다. 주제는 항상 나오는 그 떡밥입니다.

“이렇게 똑똑한 사람들이 금융권에서 마진이나 따먹고 있다니, 인류 재능의 낭비 아닌가? 농업 효율화나 신약 개발에 쓰여야지.”

여기에 대한 반박과 재반박이 흥미롭습니다.

  1. 시장의 논리: “돈은 리소스 배분의 투표권이다. 시장이 금융에 돈을 주는 건 그만큼 자원 배분이 중요하기 때문이다.”
  2. 현실적인 시각: “바이오나 농업 쪽 연봉을 봐라. 나도 화학 전공했지만 결국 IT로 왔다. 금융권이 최고의 대우를 해주니 인재가 몰리는 건 당연하다.”
  3. Jane Street의 변: Jane Street는 OCaml 같은 함수형 언어를 실무에서 가장 하드코어하게 사용하는 곳 중 하나입니다. 이들이 만들어내는 기술적 부산물(오픈소스, 컴파일러 최적화 등)이 IT 생태계 전반에 기여하는 바도 무시할 순 없습니다.

제 생각은 이렇습니다.

금융 공학(Financial Engineering)이 겉보기엔 제로섬 게임 같아 보일 수 있습니다. 하지만 그들이 극한의 레이턴시를 줄이기 위해 개발한 FPGA 기술, 고성능 네트워크 스택, 그리고 이런 미친 수준의 머신러닝 최적화 기법들은 결국 다른 산업으로 흘러들어옵니다.

우리가 지금 편하게 쓰는 PyTorch의 최적화 기법 중 일부도, 어쩌면 누군가가 주식 시장에서 1ms를 줄이기 위해 밤새 고민한 결과물일지 모릅니다.

마치며: Interpretability의 미래

이 퍼즐은 우리에게 중요한 교훈을 줍니다. “우리가 만든 모델을 우리는 얼마나 이해하고 있는가?”

수작업으로 만든 모델조차 리버스 엔지니어링하기가 이렇게 힘든데, 수천억 파라미터의 LLM 내부에서 무슨 일이 일어나는지 우리가 정말 알 수 있을까요? Jane Street는 이 퍼즐을 통해 Mechanistic Interpretability 가 얼마나 어려운지, 그리고 왜 필요한지를 아주 우아하게 보여주었습니다.

만약 여러분이 “그냥 모델 돌려서 정확도 99% 찍었습니다”에 만족하는 엔지니어라면, 이 퍼즐을 한 번 뜯어보시길 권합니다. weightbias가 단순한 숫자가 아니라, 논리를 담은 그릇이라는 걸 뼈저리게 느끼게 될 겁니다.