2011年3月1日火曜日

Emacs Lisp でシーザー暗号

暗号に関する本を読むと、たいていは「シーザー暗号 - Wikipedia」が紹介されている。

鍵そのものと暗号化アルゴリズムを分けて考えるという現代的な(?)性質は満たしているが、容易に解読できるので実用性がない、という位置づけで。

簡単なので簡単にプログラムが作れる。Emacsの *scratch*バッファでやってみるのも簡単。

仕様

  • 与えられた文字列を暗号化する。
  • 文字列はアスキー文字のみ。
  • 小文字は大文字に変換する。
  • A-Z以外の文字(スペースやピリオドなど)はそのまま。
  • 鍵(下の例で言うと仮引数の key)の値は正でも負でもいい。
  • 鍵の値が0や26、-26なら変化なし。

コード

3つの関数に分けた。

;; 入力の正規化のようなことを行ってから暗号化。すなわち、
;; 文字列を大文字に変換し、鍵を 0 から 25 までの値に変換する。
(defun my-caesar (str key)
  (my-caesar-string
   (upcase str)
   ((lambda (n) (while (< n 0) (incf n 26)) (mod n 26)) key) ))

;; 文字列を暗号化する
(defun my-caesar-string (str key)
  (if (< (length str) 1)
      ""
    (concat
     (my-caesar-string1 (substring str 0 1) key)
     (my-caesar-string (substring str 1) key))))

;; 文字を暗号化する(厳密には「文字」ではなく、文字列長が1の文字列)
(defun my-caesar-string1 (c key)
  (if (string-match "[a-zA-Z]" c)
      (char-to-string (+ ?A (mod (+ key (- (string-to-char c) ?A)) 26)))
    c))

関係ないが、組み込み関数の名前が長くてつらい(string-to-charsubstringなど)。

テスト

その1. アトム
(my-caesar "foo bar baz!" 27)
=> "GPP CBS CBA!"
その2. リスト
(mapcar (lambda (str) (my-caesar str -1))
        '("foo bar baz!" "hoge fuga piyo."))
=> ("ENN AZQ AZY!" "GNFD ETFZ OHXN.")

0 件のコメント:

コメントを投稿