Caesar 암호: PicoLisp의 간단한 암호화 시스템

클래식 알고리즘 시리즈에 오신 것을 환영합니다.여기서 우리는 Rosetta Code Project의 코드 예시를 토론하고 실현이 어떻게 작동하는지 점차적으로 설명할 것이다.우리의 첫 번째 임무는"Caesar Cipher"이다.
이 글에서 우리는 초보자 시리즈에서 알게 된 많은 것들을 만나게 될 것이다"List and Strings" functions.

과업


먼저 직접 시도해 보려면 다음 작업 설명이 필요합니다.

Implement a Caesar cipher, both encoding and decoding. The key is an integer from 1 to 25. This cipher rotates (either towards left or right) the letters of the alphabet (A to Z). The encoding replaces each letter with the 1st to 25th next letter in the alphabet (wrapping Z to A). So key 2 encrypts "HI" to "JK", but key 20 encrypts "HI" to "BC".


캐시 암호화의 작업 원리


만약 네가 암호 알고리즘을 배운 적이 있다면, 너는 캐시 암호를 만날 수 있을 것이다. 왜냐하면 그것은 이해하기 쉽기 때문이다.
그것은 로마 황제 줄리엣스 카이사의 이름으로 명명된 것이다. 왜냐하면 그가 이런 암호화 시스템을 이용하여 비밀 정보를 전송한다는 증거가 있기 때문이다.더 많은 역사적 배경see here.

자모표의 모든 자모는 고정된 걸음걸이에 따라 자리를 옮긴다는 것이 바로'코딩 키'라는 사상이다.예를 들어 키가 2라면'C'는'A','D'는'B','E'는'C'라고 쓰면 유추된다.알파벳의 끝에서'Y'는'A'가 되고'Z'는'B'가 된다.분명히 이것은 매우 안전한 암호화가 아니다. 왜냐하면 통계 방법을 사용하거나 모든 가능한 위치를 검사하면 쉽게 해독할 수 있기 때문이다.
그러나PicoLisp에서Caesar 비밀번호를 실현하는 것은 우리의Rosetta 코드 시리즈를 시작하는 좋은 예이다.그것은 순환 목록, 맵, 익명 함수 등 재미있는 개념들을 보여 주었다.'PicoLisp for 초보자'시리즈에는 이미 많은 함수가 도입되어 코드가 우아하고 간단하다.
가자!

알고리즘의 직관적 방법


우리는 어떻게 이 알고리즘을 실현해야 합니까?알파벳의 순서가 매우 중요하다는 것은 분명하다. 알파벳의 끝은 그것의 시작에 비쳐야 하기 때문이다.표지의 그림은 이 원리를 잘 설명한다.

안쪽은 일반 문자이고 바깥쪽은 암호화 문자입니다.이제 PicoLisp 에서 이를 실현해 보겠습니다.

첫 번째 단계 - 알파벳 목록 만들기


우리가 가장 먼저 필요한 것은 모든 자모표 문자의 목록이다.하나의 주요 생각은 목록을 '순환', 즉 'Z' 다음에 'A' (위의 그림의 도구) 를 만드는 것이다.PicoLisp에서는 . 기호를 통해 (1 2 3 .) 또는 circ 함수를 사용할 수 있습니다.목록을 작성합니다.
간단한 방법은: 물론 우리는 모든 자모를 수동으로 입력할 수 있다.
(setq *Letters '("A" "B" "C" ... "Z" .))
요컨대 상술한 해결 방안은 실수하기 매우 쉽다.더 좋은 방법은 ASCII encoding 을 사용하여 이 목록을 만드는 것입니다.대문자는 숫자 65에서 90까지 인코딩됩니다.그럼 다음과 같은 몇 가지를 해보겠습니다.
  • (range 65 90)->(656667...90)를 사용하여 65에서 90까지의 목록을 만듭니다.
  • 숫자는 char를 통해 문자로 변환할 수 있습니다. 예를 들어 (char 65)=A. char로 함수(mapcar char (range 65 90))를 목록에 적용합니다. -->.(“A”“B”“C”“Z”).
  • 현재 circ 함수를 알파벳마다 적용하여 목록을 순환시킵니다.(apply circ (mapcar char(...)))-->(“A”“B”“C”“Z”),그중.은'Z'이후에 다시'A'가 나타났다는 뜻이다.
  • 목록을 글로벌 변수*Letters로 설정합니다. 명명 규칙에 따라 대문자와 별표가 있습니다.
  • 우리는 다음과 같은 것을 얻었다.
    :(setq *Letters (apply circ (mapcar char (range 65 90))))
    -> ("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" .)
    

    2단계 - 단일 문자 인코딩


    인코딩하고 싶은 문자열을 가져오려고 합니다.첫 번째 단계에서는 uppc를 사용하여 모든 문자를 대문자로 변환하고 chop 함수를 사용하여 문자열을 문자 목록으로 변환합니다.
    :(chop (uppc "in vino veritas")) 
    ->("I" "N" " " "V" "I" "N" "O" " " "V" "E" "R" "I" "T" "A" "S")
    
    현재 이 자모들을 인코딩하려면, 이 함수는 모든 문자를 받아들이고 인코딩된 문자를 되돌려 주는 함수를 만들어야 한다.우리 한 걸음 한 걸음 봅시다.

  • 우선, 우리는 *Letters 함수를 사용하여 문자가 member 목록에 있는지 확인하고, 이 문자가 존재하면 이 문자에서 시작된 목록을 되돌려줍니다. 그렇지 않으면 되돌려줍니다 NIL.
    : (member "U" *Letters)                                   
    -> ("U" "V" "W" "X" "Y" "Z" "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" .)
    : (member "D" *Letters)
    -> ("D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "A" "B" "C" .)
    
  • 보시다시피 member 함수는 해당 자모로부터 시작된 *Letters 목록을 되돌려줍니다.현재 우리는 암호 key 가 붙은 알파벳을 인코딩하려고 한다.목록을 이동하려면 nth 함수를 사용하여 목록과 정수 값을 가져오고 이 값에서 시작된 목록의 끝을 반환합니다.
  • :(nth (member "U" *Letters) 2))
    -> ("V" "W" "X" "Y" "Z" "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" .)
    :(nth (member "D" *Letters) 6)
    -> ("I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "A" "B" "C" "D" "E" "F" "G" "H" .)
    
  • 점점 가까워지고 있지만 nth가 되돌아오는 목록을 검사할 때, 우리는 실제적으로 위치 이동 목록의 두 번째 항목을 원합니다. 왜냐하면 nth 함수는 (key -1) 위치로만 위치를 이동하기 때문입니다.두 번째 항목을 얻기 위해서, 우리는 cadr 을 사용합니다. 이것은 cdrcar 의 줄임말입니다.carcdr가 무슨 뜻인지 확실하지 않으면 다시 읽으세요this post.
  • : (cadr (nth (member "U" *Letters) 2)))
    -> "W"
    : (cadr (nth (member "D" *Letters) 6))
    -> "J"
    

    3단계 - 통합


    첫 번째 단계에서, 우리는 입력 문자열을 하나의 목록으로 잘라내고, 두 번째 단계에서, 우리는 각각 이 자모들을 인코딩하려고 한다.이제 우리 함께 하자.
    우리는 입력 문자열의 모든 자모를 가져오고 모든 요소에 우리의 인코딩 함수를 적용하기를 희망한다. 이것은 mapcar 의 전형적인 응용이다.mapcar 함수와 목록을 매개 변수로 한다.그런데 우리 기능이 뭐야?분명히 우리는 이렇게 정의할 수 있다.
    (de encodeChar (C)
        (cadr (nth (member C *Letters) Key))) )
    
    mapcar에 맡긴다.그러나 실제로 우리는 인코딩 함수를 한 번만 필요로 하기 때문에 이를 익명 함수로 정의하는 것이 (구조와 읽기 용이성 면에서) 더 좋은 선택이 될 수 있다.
    초보자 강좌에서 기억할 수 있는 것처럼 익명 함수의 문법은 '(args) (function)' 이기 때문에 다음과 같이 정의할 수 있습니다.
    :'((C) (cadr (nth (member C *Letters) Key)))
    
    여기서 C는 인코딩할 문자입니다.
    슬라이드 목록에 익명 함수 호출 mapcar 을 만들고 테스트하기 key = 3 를 사용합니다.
    : (setq TestStr (chop (uppc "in vino veritas")))
    -> ("I" "N" " " "V" "I" "N" "O" " " "V" "E" "R" "I" "T" "A" "S")
    : (mapcar '((C) (cadr (nth (member C *Letters) 3))) TestStr)
    -> ("L" "Q" NIL "Y" "L" "Q" "R" NIL "Y" "H" "U" "L" "W" "D" "V")
    
    이것은 이미 희망적으로 보인다. 적어도 역할 전환은 지금 보기에 옳다.
    현재, 마지막 단계로, 우리는 이 단일 자모들을 문자열로 바꾸어야 한다. 우리는 pack 함수를 사용하여 실현할 수 있다.우리는 그것을 mapcar 함수에 포장하여 다음과 같은 것을 얻었다.
    : (pack (mapcar '((C) (cadr (nth (member C *Letters) 3))) TestStr))
    -> "WKLVLVDWHVW"
    
    보시다시피 공백과 문장부호로 만든 값NIL도 자동으로 삭제했습니다.

    4단계 - 스크립트 완료


    이제 작은 발로 끝내자.우리는 다음 구문을 사용하여 그것을 호출하기를 희망합니다. ./caesar-cipher.l <plain-string> <key> 예를 들어:
    $ ./caesar-cipher.l "In vino veritas" 7
    PUCPUVCLYPAHZ
    
    "A very first PicoLisp Program" - 게시물에서 알 수 있듯이 우리는 <plain-string>로 두 개의 매개 변수<key>opt를 검색할 수 있다.opt가 문자열로 변환되므로 함수format를 사용하여 키를 문자열에서 정수로 변환하고 글로벌 변수*PlainStr*Key에 저장해야 합니다.
    #! /usr/bin/picolisp /usr/lib/picolisp/lib.l
    
    # first command line parameter: plain string
    (setq *PlainStr (opt))
    
    # second command line parameter: key (integer)
    (setq *Key (format (opt)))
    
    또한 전역 *Letters 목록을 정의해야 합니다. 물론 인코딩 함수 caesar 도 있습니다. 문자열과 키를 매개 변수로 하고 인코딩된 문자열을 되돌려줍니다.
    (setq *Letters (apply circ (mapcar char (range 65 90))))
    
    (de caesar (Str Key)
       (pack
          (mapcar '((C) (cadr (nth (member C *Letters) Key)))
             (chop (uppc Str)) ) ) )
    
    마지막으로, 우리는 명령행 매개 변수를 사용하여 caesar 함수를 호출하고 결과를 출력합니다.
    (prinl (caesar *PlainStr *Key))
    
    이후 우리는 bye로 통역사에서 물러났다.
    망했다!
    최종 스크립트는 here에서 다운로드할 수 있습니다.단계: 스크립트를 다운로드합니다(예: curl 사용).
    $ curl https://gitlab.com/picolisp-blog/single-plage-scripts/-/raw/main/rosetta/caesar-cipher.l -o caesar-cipher.l
    
    실행 가능:
    $ chmod +x caesar-cipher.l
    
    빨리 뛰어!
    $ ./caesar-cipher.l "In vino veritas" 7
    PUCPUVCLYPAHZ
    
    '로제타 비밀번호'시리즈의 첫 부분이니 마음에 드셨으면 좋겠습니다.
    내일 우리는 PicoLisp의 set 함수를 더욱 상세하게 이해하여 Rosetta 코드의 "100 Doors Task"를 준비할 것이다.

    출처

  • 표지: https://upload.wikimedia.org/wikipedia/commons/thumb/b/b5/CipherDisk2000.jpg/800px-CipherDisk2000.jpg

  • https://rosettacode.org/wiki/Caesar_cipher#PicoLisp

  • https://software-lab.de/doc/index.html
  • 좋은 웹페이지 즐겨찾기