'Khoor Zruog!', 시저가 말한다.
Source: Dev.to
로마 진영의 이야기
조용한 로마 진영에서, 한 사신이 기다리고 — 그리고 알파벳은 비밀스러운 작은 발걸음을 배웁니다. 촛불은 낮았고, 밤은 가죽 끈이 자리 잡는 소리, 갑옷이 내려지는 소리, 그리고 내일의 계획이 되려는 천 가지 조용한 생각들처럼 들렸습니다. 사신은 작은 판을 들고 있었으며, 모든 메시지가 모든 눈에 보여야 하는 것은 아니었습니다. 일부 명령은 잘못된 손에 의해 이해되지 않도록 거리를 넘어 전달되어야 했습니다. 바로 그때 알파벳이 이야기에 등장합니다.
시저 암호: 역사와 원리
알파벳은 생각보다 가르치기 쉽고, 떠들어 놓기엔 어려운 존재입니다. 단순히 일정한 단계만큼 이동하도록 하면 됩니다. 율리우스 시저도 바로 그렇게 했습니다. 우리가 시저 암호라고 부르는 이유는 그가 글자를 이동시키는 아이디어를 만든 것이 아니라, 개인 및 군사 통신을 보호하기 위해 이를 사용한 최초의 유명 인물로 기록되었기 때문입니다.
로마 역사가 수에토니우스는 시저가 “단어가 전혀 드러나지 않게” 비밀 메모를 쓰기 위해 글자를 이동시켰다고 설명하면서, 규칙을 이렇게 제시합니다: A를 D로 바꾸고, 그 이후로 계속한다. 이 “A를 D로”라는 한 줄 요약이 바로 비밀의 전부이며, 이는 3칸 이동을 의미합니다.
A → D
B → E
C → F
…
알파벳의 끝에 도달하면 다시 시작점으로 돌아갑니다. 시저는 전투 지시를 장군들에게, 그리고 신뢰하는 친구들에게 개인 편지를 보낼 때 이 방식을 사용했다고 전해지며, 이는 가로채기에는 번거롭고 읽기에는 훨씬 어려웠습니다.
당시 이 암호가 현대인에게 들리는 것보다 더 효과적이었던 두 가지 실용적인 이유가 있습니다:
- 문해율이 낮았다.
- 체계적인 암호 해독이 아직 표준 기술이 아니었다.
빈도 분석, 즉 많은 단순 암호를 깨는 “아하” 순간은 9세기에 알‑킨디가 제시했습니다. 수에토니우스는 또한 시저의 후계자 옥타비아누스(아우구스투스)가 더 부드러운 1칸 이동(B를 A로, C를 B로…)을 사용했다고 기록합니다. 일부 기록에 따르면, 옥타비아누스는 Z를 A로 바꾸는 대신 AA를 Z 대신 썼다고 합니다.
파이썬으로 시저 암호 구현하기
이천 년이 흐른 지금, 캠프파이어는 노트북 화면이 되고, 사신은 함수 호출이 되며, 알파벳은 우리가 요구할 때마다 여전히 걸어갑니다. 아래는 시저 이동을 이용해 메시지를 암호화하고 복호화하는 깔끔한 파이썬 구현 예시입니다.
def caesar_cipher(text, shift, encrypt=True):
if not isinstance(shift, int):
return 'Must be an integer.'
if shift > 26:
return 'Must be between 1 and 26.'
if not encrypt:
shift = -shift
abc = 'abcdefghijklmnopqrstuvwxyz'
abc_shift = abc[shift:] + abc[:shift]
t = str.maketrans(abc + abc.upper(),
abc_shift + abc_shift.upper())
return text.translate(t)
def encrypt(text, shift):
return caesar_cipher(text, shift)
def decrypt(text, shift):
return caesar_cipher(text, shift, encrypt=False)
print(encrypt('Hello World!', 3)) # Output: Khoor Zruog!
print(decrypt('Khoor Zruog!', 3)) # Output: Hello World!
코드 작동 방식
- 검증 – 함수는 이동값이 정수이며 1~26 사이인지 확인합니다.
- 방향 –
encrypt가False이면 이동값을 부호 반대로 바꾸어 동일한 로직을 복호화 알고리즘으로 전환합니다. - 알파벳 설정 –
이는 Z를 지나면 A로 돌아가는 “원형”을 만듭니다.abc = 'abcdefghijklmnopqrstuvwxyz' abc_shift = abc[shift:] + abc[:shift] - 번역 테이블 –
소문자와 대문자를 모두 처리합니다.t = str.maketrans(abc + abc.upper(), abc_shift + abc_shift.upper()) - 번역 적용 –
text.translate(t)는 각 문자를 이동된 알파벳을 통해 변환합니다.
보조 함수 encrypt와 decrypt는 적절한 플래그만 설정하는 얇은 래퍼입니다.