암호학을 맛보는 프로젝트이다.
암호학의 목표 중 하나는 키를 사용하여 평문을 읽을 수 없는 비문으로 암호화하고 이를 다시 평문으로 복호화하는 것이다.
우리는 미국 남북 전쟁에서 사용된 2개의 암호, 루트 전치 암호(북부)와 레일 펜스 암호(북부, 남부)를 탐구한다.
- 루트 전치 암호가 뭔가요?
전치 암호(위키피디아)
위키피디아와 이 책에서 말하는 바에 따르면 전치 암호는 간단히 말해서 단어 속 글자들의 순서를 바꾸는 것이라 보면 된다.
루트 전치 암호를 더 잘 이해하기 위해서 우리만의 루트 전치 암호를 작성해볼 것인데, 이를 제어 메시지라고 부른다.
one | two | three | four |
---|---|---|---|
0 | 1 | 2 | 3 |
4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 |
키는 루트의 순서와 방향을 알려준다.
음수는 하단에서 위로 올라간다는 뜻이고, 양수는 그 반대의 의미를 가진다.
Load the ciphertext string.
Convert ciphertext into a cipherlist to split out individual words.
Get input for the number of columns and rows.
Convert key into a list to split out individual numbers.
Create a new list for the translation matrix.
For every number in the key:
Create a new list and append every n items (n = # of rows) from the cipherlist.
Use the sign of key number to decide whether to read the row forward or backward.
Using the chosen direction, add the new list to the matrix. The index of each new list is based on the column number used in the key.
Create a new string to hold translation results.
For range of rows:
Remove the last word in nested list
Add the word to the translation string.
Print the translation string.
ciphertext = "16 12 8 4 0 1 5 9 13 17 18 14 10 6 2 3 7 11 15 19"
# 각각의 요소를 단어로 나눈다(글자로 나누는 것이 아님!!!)
cipherlist = list(ciphertext.split()) # 1번
# 초기 변수 값 설정하기
COLS = 4 # 가로
ROWS = 5 # 세로
key = '-1 2 -3 4'
translation_matrix = [None] * COLS
plaintext = ''
start = 0
stop = ROWS
# key_int를 정수형 리스트로 변환
key_int = [int(i) for i in key.split()] # 2번
# turn columns into items in list of lists
for k in key_int:
if k < 0: # reading bottom-to-top of column
col_items = cipherlist[start:stop]
elif k > 0: # reading top-to-bottom of column
col_items = list((reversed(cipherlist[start:stop]))) # reversed method
print(col_items) # type: ignore
translation_matrix[abs(k) - 1] = col_items # type: ignore # 3번
start += ROWS
stop += ROWS
print("\nciphertext = {}".format(ciphertext))
print("\ntranslation matrix =", *translation_matrix, sep="\n")
print("\nkey length = {}".format(len(key_int)))
# loop through nested lists popping off last item to new list:
for i in range(ROWS):
for col_items in translation_matrix:
word = str(col_items.pop()) # type: ignore # 4번
plaintext += word + ''
print("\nplaintext = {}".format(plaintext))
cipherlist = list(ciphertext.split())
list1 = list(range(4))
굳이 split매서드로도 리스트로 나타낼 수 있는데 list()를 사용한 이유는 새로운 list를 만들고 싶어서이다.(나중에 ciphertext를 출력하기때문)
key_int = [int(i) for i in key.split()]
number = []
for i in range(1, 10):
number.append(i)
위와 같은 리스트를 생성하는 코드를 다음과 같이 리스트 컴프리헨션으로 표기할 수 있다.
[i for i in range(10)]
이미지로 보면 다음과 같다.
이미지 출처: https://wikidocs.net/22805
translation_matrix[abs(k) - 1] = col_items
for i in range(ROWS):
for col_items in translation_matrix:
word = str(col_items.pop()) # type: ignore
list = [1, 2, 3, 4]
element1 = list.pop() # 위치 지정 안함
element2 = list.pop(0) # 위치 지정 함
print(element1) # >>> 4
print(element2) # >>> 1
print(list) # >>> [2, 3]
위치를 지정한다면 지정 위치의 요소를 제거하고 제거된 요소를 반환한다.
위치를 지정하지 않으면 바로 아래에서 살펴볼 stack자료구조로 가장 마지막 요소가 제거되고 그 요소를 반환한다.
자료 참고
str()
문자열 형태로 객체를 반환해서 return 하는 함수이다. 위의 코드에서는 plaintext를 완성하는 과정에서 행의 숫자들을 모아 연결해야 하기에 str()를 사용했다.
#type: ignore
#type: ignore에 대한 설명
You can use the form # type: ignore[code] to only ignore specific errors on the line. This way you are less likely to slience unexpected errors that are not safe to ignore, and this will also document what the purpose of the comment is.
추가 자료(mypy 1.0.1 documentation)
It's possible to silence specific error codes on a line using # type: ignore[code]. This way you won't accidentally ignore other, potentially more serious errors.