🔐

TOYPRO解説記事 - 暗号(500点)

2021/04/22に公開約3,300字

1. 概要

競技プログラミングのサイト「TOYPRO」の300点問題、暗号の解説をします!

問題ページはこちら: https://app.toy-pro.net/user/questions/140

お急ぎの方は3節まで。

2. 問題

太郎くんは暗証番号を入力した時に他の人に解読されないように暗号化するプログラムを思いついきました。

入力されたアルファベットを、aは0, bは1, …., zは25という風に数字に置き換えます。

置き換えた数字の3倍した数字を26で割った余りが新しい数字となります。

そしてその数字をアルファベットに変換した物が暗号化されたアルファベットになります。

例えば、abと入力された場合を考えてみましょう。

abをそれぞれ数字に変換すると01です。

01をそれぞれ3倍して26で割った余りは03です。

そしてこの数字をアルファベットに変換するとadとなり、これが暗号化された文字列となります。

それではアルファベット(小文字のみ)を入力してそれを暗号化されたアルファベットをprintするプログラムを書いてください。

必要な変数

password

入力例1

password = "abcd"

出力例1

adgj

入力例2

password = "AAAA"

出力例2

エラー

3. 解説

あってはいるけど見づらい例

一応方法は2つあります。

1つ目は頑張って辞書(dict型)またはtuple(or list)型に文字と数字の対応表を作っていく方法です。

今回はdisct型を使用してみようと思います。

password = "abcd" # 必要な変数を定義
pass2num = {"a": 0, "b": 1, "c": 2, "d": 3, "e": 4, "f": 5, "g": 6, "h": 7, "i": 8, "j": 9, "k": 10, "l": 11, "m": 12, "n": 13, "o": 14, "p": 15, "q": 16, "r": 17, "s": 18, "t": 19, "u": 20, "v": 21, "w": 22, "x": 23, "y": 24, "z": 25} # 対応表作成
enc = "" # 数字化された文字列を入れる変数を定義
txt = "" # 暗号化された文字列を入れる変数を定義


if password.lower() == password: 
    # lowerで小文字にして元のpasswordと違うかを比べる。
    # これによって大文字が含まれているかがわかる(大文字があったらlowerで小文字にされるため)
    
    # 数字化をする
    for i in password: # これで1文字ずつpasswordの文字がiにaから順に文字が入っていく
        enc += str(pass2num[i]*3%26) #対応表から数字を取り出して3倍して26を割ったあまりをencに入れる
    
    # 暗号化をする
    for i in enc: # これで1文字ずつencの文字がiにaから順に文字が入っていく
        # 辞書の逆引きをする
        # 参考サイト: https://note.nkmk.me/python-dict-get-key-from-value/
        txt += [k for k, v in pass2num.items() if v == int(i)][0]
        
    # 暗号化された文字列を表示する
    print(txt)
else:
    print("エラー")

詳しい説明はコメントで書かれていますので読んでみてください。

この対応表、自力で書こうとは到底思えませんよね...(面倒くさがり)

どうするの?

一旦はなしからそれて、パソコン(プログラム)での文字の認識をどのようにしているのかを考えてみましょう。

パソコン(プログラム)は2進数(0と1で作られている数字の羅列)ですべての物事を解釈しています。

では、何故プログラムは人間にも読めるようになっているし、パソコンは日本語や英語などが表示できるのでしょうか。

それは、パソコン(プログラム)の中に先程のような対応表(文字コードという)が存在するからです。

いろいろな理由があり、文字コードは昔(30年ほど前)から様々なものが開発されてきました。

日本語だけのものもあれば、英語だけ、ロシア語だけというものもあります。

中にはそのすべてをカバーしていて更には特殊文字(←など)や絵文字(🥺など)もカバーしているものがあります。

それはunicodeといってPC界隈で今最もメジャーな文字コードになっています。

ただし、今回は英文字だけなので英数字を扱う中で一番メジャーなASCIIという文字コードを使っていこうと思います。

詳しくはこちらを見てみてください。 https://gihyo.jp/book/pickup/2019/0006

pythonにはその対応している数字と文字を変換する機能が標準でついています。

ord関数とchr関数です。

使い方について詳しくはこちらを見てみてください。 https://qiita.com/ell/items/6eb48e934a147898d823

美しい例(想定解...?)

password = "abcd" # 必要な変数を定義
enc = "" # 数字化された文字列を入れる変数を定義
txt = "" # 暗号化された文字列を入れる変数を定義


if password.lower() == password: 
    # lowerで小文字にして元のpasswordと違うかを比べる。
    # これによって大文字が含まれているかがわかる(大文字があったらlowerで小文字にされるため)
    
    # 数字化をする
    for i in password: # これで1文字ずつpasswordの文字がiにaから順に文字が入っていく
        enc += str((ord(i)-97)*3%26) # ord関数を使って数値化する

    # 暗号化をする
    for i in enc: # これで1文字ずつencの文字がiにaから順に文字が入っていく
        txt += chr(int(i)+97) # chr関数を使って暗号化をする
        
    # 暗号化された文字列を表示する
    print(txt)
else:
    print("エラー")

これで美しくなりました。

4.さいごに

この記事を読んでくださりありがとうございます。
記事の間違いを見つけた場合や、質問がある場合、解説を書いてほしい問題がある場合はスクラップで連絡してくれると嬉しいです。

Discussion

ログインするとコメントできます