今日は,謎解きの日です.ということで,Xで暗号の謎解き問題を紹介しました.
実はこれ,あの上杉謙信が使った「字変四十八の奥義」という暗号なんです!基本原理は,古代ギリシア時代に発明されたポリュビオス暗号と同じ座標式暗号の一種です.
この謎解きの過程は,情報分野では「解読」といいます.
座標式暗号
座標式暗号とは,以下のような列番号と行番号を使って暗号化するという単純なものです.
例:い→11 ろ→21
上杉暗号 | 1列 | 2列 | 3列 | 4列 | 5列 | 6列 | 7列 |
---|---|---|---|---|---|---|---|
1行 | い | ろ | は | に | ほ | へ | と |
2行 | ち | り | ぬ | る | を | わ | か |
3行 | よ | た | れ | そ | つ | ね | な |
4行 | ら | む | う | ゐ | の | お | く |
5行 | や | ま | け | ふ | こ | え | て |
6行 | あ | さ | き | ゆ | め | み | し |
7行 | ゑ | ひ | も | せ | す | ん |
今回は,江戸時代頃から一般的に使われるようになった「゛」(濁点)を77に追加した以下の表を用いて暗号化しました.
尾教暗号 | 1列 | 2列 | 3列 | 4列 | 5列 | 6列 | 7列 |
---|---|---|---|---|---|---|---|
1行 | い | ろ | は | に | ほ | へ | と |
2行 | ち | り | ぬ | る | を | わ | か |
3行 | よ | た | れ | そ | つ | ね | な |
4行 | ら | む | う | ゐ | の | お | く |
5行 | や | ま | け | ふ | こ | え | て |
6行 | あ | さ | き | ゆ | め | み | し |
7行 | ゑ | ひ | も | せ | す | ん | ゛ |
解いてみよう
暗号文は「43 56 75 63 77 61 76 55 77 43」でした.暗号表をみると3行4列目はう,5行6列目はえ…ととくことができます.
ということで答えは「うえすき゛あんこ゛う」です!!
このように知っている手順に沿って暗号文を戻すことを復号といいます.
プログラミング
さて,この暗号,表を見ながら変換する必要があるので面倒臭かったです.ということで,ChatGPTを使いつつプログラミングしてみました.
def encode_uesugi(plain_text: str) -> str:
# 変換表を定義
conversion_table = [
["い", "ろ", "は", "に", "ほ", "へ", "と"],
["ち", "り", "ぬ", "る", "を", "わ", "か"],
["よ", "た", "れ", "そ", "つ", "ね", "な"],
["ら", "む", "う", "ゐ", "の", "お", "く"],
["や", "ま", "け", "ふ", "こ", "え", "て"],
["あ", "さ", "き", "ゆ", "め", "み", "し"],
["ゑ", "ひ", "も", "せ", "す", "ん", "゛"]
]
# 対応辞書を作成
char_to_code = {}
for y in range(7):
for x in range(7):
c = conversion_table[y][x]
char_to_code[c] = f"{y+1}{x+1}"
# 平文を暗号化
result = []
for c in plain_text:
if c in char_to_code:
result.append(char_to_code[c])
else:
result.append(c) # 辞書にない文字はそのまま出力
return " ".join(result) # 空白で区切って返す
def decode_uesugi(cipher_text: str) -> str:
# 変換表を定義
conversion_table = [
["い", "ろ", "は", "に", "ほ", "へ", "と"],
["ち", "り", "ぬ", "る", "を", "わ", "か"],
["よ", "た", "れ", "そ", "つ", "ね", "な"],
["ら", "む", "う", "ゐ", "の", "お", "く"],
["や", "ま", "け", "ふ", "こ", "え", "て"],
["あ", "さ", "き", "ゆ", "め", "み", "し"],
["ゑ", "ひ", "も", "せ", "す", "ん", "゛"]
]
answer = ""
# 空白で区切ってリスト化
codes = cipher_text.split()
# 各コードをデコード
for code in codes:
if len(code) == 2 and code.isdigit():
col = int(code[0])
row = int(code[1])
char = conversion_table[col - 1][row - 1]
answer += char
else:
answer += code # もし数字2桁じゃないならそのまま加える
return answer
# メイン実行部
plain = input("平文をひらがなで入力してください:")
cipher = encode_uesugi(plain)
print("暗号文:", cipher)
decoded = decode_uesugi(cipher)
print("復号結果:", decoded)
Pythonで書かれています.いろは歌を並べた7×7の表を変換表(conversion_table)としてに,それぞれの文字に「列番号+行番号」の2桁の数字を割り振ります.
- 暗号化(encode_uesugi)では,入力されたひらがなを1文字ずつ見て,対応する数字2桁に変換し,1文字ごとに空白で区切って並べます
- 復号(decode_uesugi)では,暗号文を空白ごとに区切って,それぞれの2桁の数字から,元のひらがなに戻します
参考文献に日本語プログラミング言語「なでしこ」で書く詳しい解説があるので是非ご覧ください.
さいごに
というわけで,今日は「上杉暗号」とそのプログラムについて紹介しました!
歴史に触れつつ,ちょっとしたプログラミングも楽しめる謎解き,よかったらみなさんも挑戦してみてくださいね!
参考
稲葉茂勝,暗号学,今人舎,2016. カーリル
クジラ飛行机,”ゼロからはじめてみる日本語プログラミング「なでしこ」(74) 戦国時代に上杉謙信が使った”上杉暗号”を使ってみよう”,https://news.mynavi.jp/techplus/article/nadeshiko-74/,Tech+,2022-09-08(2025-4-27).