見出し画像

③エニグマ暗号機のローター結線解読プロジェクト(コードが書けた?!)

Claudeが他の案件で忙しいのであまり手がつかない。
が、気になるコードが書けた。

実行環境:Raspberry Pi4 ModelB 4GB

最初は文法エラー、次はメモリ不足。
何度も何度もやり直してもらって、やっとなんとか動き出したのがこちら。
まずは自分が解読しなくてはな。

cycleStructure[perm_] := Sort[Length /@ (Cycles[perm])];

(*Function to generate random permutation with given cycle structure*)
randomPermWithStructure[structure_] :=
 Module[{n = Total[structure], cycles, perm},
  cycles = Table[RandomSample[Range[n], k], {k, structure}];

perm = Range[n];

Do[perm[[cycle]] = RotateLeft[perm[[cycle]]], {cycle, cycles}];
perm]

(*Function to apply permutation*)
applyPerm[perm_, x_] := perm[[x]]

(*Function to calculate match score*)
matchScore[a_, b_, plaintext_, ciphertext_] :=
Module[{m = Length[plaintext], scores},
 scores = Table[Count[
      Table[applyPerm[a,
      applyPerm[RotateLeft[b, r],
      plaintext[[i]]]] == ciphertext[[i]],
     {i, 1, m}], True]/m, {r, 0, 25}];
     Max[scores]]

 (*Main cryptanalysis function*)
cryptanalysis[plaintext_, ciphertext_, sampleSize_ : 1000,
 matchThreshold_ : 0.5] :=
  Module[{n = 26, possibleStructures, bestA, bestB, bestScore = 0,
  currentScore},(*Generate possible cycle structures*)
  possibleStructures = IntegerPartitions[n];

  (*Iterative sampling and scoring*)
 
Do[Module[{a =
  randomPermWithStructure[RandomChoice[possibleStructures]],
 b = randomPermWithStructure[RandomChoice[possibleStructures]]},
  currentScore = matchScore[a, b, plaintext, ciphertext];
 If[currentScore > bestScore, bestScore = currentScore;
 bestA = a;
 bestB = b;];], {sampleSize}];

(*Return results*)
<|
"BestA" -> If[bestScore >= matchThreshold, Cycles[bestA], {}],
"BestB" -> If[bestScore >= matchThreshold, Cycles[bestB], {}],
"BestMatchScore" -> bestScore|>]

(*Example usage*)
plaintext = {1, 2, 3, 4, 5, 6};
ciphertext = {15, 22, 3, 18, 9, 7};
result = cryptanalysis[plaintext, ciphertext];

Print["Best cycle structure for A: ", result["BestA"]];
Print["Best cycle structure for B: ", result["BestB"]];
Print["Best match score: ", result["BestMatchScore"]];

(*Function to convert cycles to readable format*)
cyclesToReadable[cycles_] :=
Map[Function[cycle,
StringJoin[Riffle[CharacterRange["A", "Z"][[cycle]], "\[Rule]"]]],
cycles]

(*Display readable cycle structures*)
Print["Readable cycle structure for A: ",
   cyclesToReadable[result["BestA"]]
];
Print["Readable cycle structure for B: ",
   cyclesToReadable[result["BestB"]]
];

Claudeが考えたコード

Best cycle structure for A: Cycles[{1,7,19,4,6,11,13,8,9,10,14,15,23,2,25,16,20,18,17,12,21,22,26,24,3,5}]
Best cycle structure for B: Cycles[{2,13,3,23,24,4,12,8,26,19,11,18,20,14,6,16,17,7,5,15,21,22,1,25,10,9}]
Best match score: 1/2
Readable cycle structure for A:
Cycles[A->G->S->D->F->K->M->H->I->J->N->O->W->B->Y->P->T->R->Q->L->U->V->Z->X->C->E]
Readable cycle structure for B:
Cycles[B->M->C->W->X->D->L->H->Z->S->K->R->T->N->F->P->Q->G->E->O->U->V->A->Y->J->I]

実行結果


少しづつ理解してみよう。今度はGeminiに聞く。
(Claudeはこれで使い切る訳にはいかない)
structure部分巡回群の長さを指定して対称群を作る為の設定そのものらしい。置換群のリストではない。
既に自分では書けないレベルに入っている!

randomPermWithStructure[structure_] にて
structureはどんな中身になってますか?例をあげて

質問プロンプト

randomPermWithStructure[structure_] の structure について

randomPermWithStructure[structure_] 関数は、与えられた structure に基づいてランダムな置換を生成する関数です。この structure は、生成される置換のサイクル構造を指定するためのリストです。

structure の要素整数: 各要素は、置換におけるサイクルの長さを表します。
リスト: 複数のサイクルの長さを表すリストを要素として持つことができます。

structure の例単純な例:
structure = {3, 2}: 3つの要素からなるサイクルと、2つの要素からなるサイクルを持つ置換を生成します。
structure = {5}: 5つの要素からなる一つのサイクルを持つ置換を生成します。

複雑な例:
structure = {{2, 2}, 3}: 2つの要素からなるサイクルが2つと、3つの要素からなるサイクルを持つ置換を生成します。
structure = {1, 1, 1, 1, 1}: すべての要素が1つのサイクルを持つ、つまり恒等置換を生成します。

structure と置換の関係サイクル: 置換は、いくつかのサイクルに分解できます。サイクルとは、ある要素が他の要素に移され、それがまた別の要素に移され、最終的に最初の要素に戻ってくるような一連の置換のことです。
サイクルの長さ: サイクルの長さは、そのサイクルに含まれる要素の数です。
structure との対応: structure の各要素は、置換のそれぞれのサイクルの長さに対応します。

回答

Do[perm[[cycle]] = RotateLeft[perm[[cycle]]], {cycle, cycles}];perm]
の意味を知りたいです

質問プロンプト

Do[perm[[cycle]] = RotateLeft[perm[[cycle]]], {cycle, cycles}]; perm] 

このコードは、置換の生成 という処理を行っています。
もう少し詳しく見ていきましょう。

コードの各部分の説明Do[…, {cycle, cycles}]:
Do: Mathematicaの繰り返し処理を行う関数です。
perm[[cycle]] = RotateLeft[perm[[cycle]]]:
perm は、生成中の置換を表すリストです。
cycle は、置換のサイクルを表す部分リストのインデックスです。
RotateLeft[perm[[cycle]]]: perm の cycle 番目の部分リストを左に1つ回転させる関数です。つまり、そのサイクル内の要素を1つずつずらす操作になります。
{cycle, cycles}: cycle 変数を cycles リストのすべての要素で繰り返し、上記の操作を行います。

全体的な動作初期化: perm には、1からnまでの整数のリストが格納されています。
サイクルごとの回転: cycles に含まれる各サイクルに対して、perm の対応する部分リストを左に回転させます。
置換の完成: すべてのサイクルに対して回転処理が終わると、perm には、指定されたサイクル構造を持つ置換が格納されます。


例えば、cycles = {{1, 2}, {3, 4, 5}} の場合、perm は最初は {1, 2, 3, 4, 5} ですが、このコードを実行すると、{2, 1, 4, 5, 3} のような置換が得られます。これは、最初の2つの要素を交換し、残りの3つの要素を左に1つ回転させた状態です。

まとめ
このコードは、与えられたサイクル構造に基づいて、ランダムな置換を生成するための重要な部分です。cycles に異なるサイクル構造を与えることで、様々な種類の置換を生成することができます。

回答

applyPerm[perm_, x_] := perm[[x]]
の意味を知りたいです

質問プロンプト

applyPerm[perm_, x_] := perm[[x]] の意味

このコードは、置換を要素に適用する という操作を表しています。
もう少し詳しく解説すると、以下のようになります。

コードの各部分の説明
applyPerm[perm_, x_]:
applyPerm:
関数の名前です。この関数に、置換と適用したい要素を渡します。
perm: 置換を表すリストです。
例えば、{3, 1, 2} のようなリストが考えられます。

x: 置換を適用したい要素です。
:= perm[[x]]:

:=: 遅延評価を表す記号です。関数呼び出し時に初めて計算が行われます。

perm[[x]]:
リスト perm の x 番目の要素を取り出す操作です。


全体的な動作
この関数は、与えられた置換 perm を、要素 x に適用します。具体的には、perm の x 番目の要素を結果として返します。

例:
perm = {3, 1, 2}; (* 置換 {1 -> 3, 2 -> 1, 3 -> 2} を表す *)
x = 2; (* 要素 2 に置換を適用する *)
result = applyPerm[perm, x]

このコードを実行すると、result には 1 が代入されます。これは、置換 perm によって、要素 2 が 1 に対応付けられているためです。

置換の考え方
置換とは、ある集合の要素を他の要素に一対一に対応させる規則のことです。上の例では、{1, 2, 3} の要素をそれぞれ {3, 1, 2} に対応させています。

applyPerm 関数は、この置換の規則に従って、ある要素がどの要素に対応するかを求めるための関数です。

まとめapplyPerm 関数は、置換を要素に適用する関数です。
与えられた置換 perm と要素 x に対してperm の x 番目の要素を返します。
この関数は、置換に関する様々な計算を行う際に利用されます。

回答

matchScore[a_, b_, plaintext_, ciphertext_] :=
Module[{m = Length[plaintext], scores},
 scores = Table[Count[
      Table[applyPerm[a,
      applyPerm[RotateLeft[b, r],
      plaintext[[i]]]] == ciphertext[[i]],
     {i, 1, m}], True]/m, {r, 0, 25}];
     Max[scores]]
の意味を知りたいです。日本語で解説してください。

質問プロンプト

matchScore 関数の解説
関数の目的
この matchScore 関数は、暗号解読において、二つの置換 a と b が、平文と暗号文をどれだけうまく対応させているかを評価するためのスコアを計算します。
より具体的には、与えられた置換 a と b を用いて平文を暗号文に変換した際に、どれだけ元の暗号文と一致するかを数値で表します。

各部分の解説matchScore[a_, b_, plaintext_, ciphertext_]:
 a, b      : 二つの置換を表すリストです。
 plaintext : 平文を表すリストです。
 ciphertext  : 暗号文を表すリストです。

Module[{m = Length[plaintext], scores}, ...]:
 Module: 局所変数を定義するための関数です。
 m   : 平文の長さを表す変数です。
 scores : さまざまな回転量 r に対する一致率を格納するリストです。

scores = Table[..., {r, 0, 25}]:
 Table: リストを生成する関数です。r を 0 から 25 まで変化させながら、 
      以下の計算を繰り返し、その結果を scores に格納します。

Count[Table[...], True]/m:
Table[applyPerm[a, applyPerm[RotateLeft[b, r], plaintext[[i]]]] == ciphertext[[i]], {i, 1, m}]:
 RotateLeft[b, r]: 置換 b を r 文字分左に回転させたものを表します。

 applyPerm[a, applyPerm[RotateLeft[b, r], plaintext[[i]]]]:
平文の i 番目の文字をb を回転させた物とaで順に置換した結果を表します。
 == ciphertext[[i]]:
上記の結果が、暗号文の i 番目の文字と一致するかを判定します。

 Count[..., True]:
上記の判定が True になった回数を数えます。
 
 /m:
全体の文字数で割ることで、一致率を計算します。

 Max[scores]:
scores の要素の中で最大の値、最も一致率が高かったものを返します。


全体的な処理の流れ平文と暗号文の長さを取得:
平文の長さを m に代入します。

様々な回転量で試す:
置換 b を 0 から 25 文字分まで回転させ、以下の処理を繰り返します。
平文の各文字を、b と a で順に置換します。
置換後の文字が、対応する暗号文の文字と一致するかを調べます。
一致した文字数を数え、全体の文字数で割ることで一致率を計算します。

最大の一致率を返す:
すべての回転量に対する一致率の中で、最も高いものを matchScore の結果として返します。

この関数の意味
この関数は、二つの置換 a と b が、ある暗号化方式において、平文と暗号文を正しく対応させている可能性を数値で評価するための指標を提供します。一致率が高いほど、a と b が正しい置換である可能性が高くなります。

まとめ この matchScore 関数は、暗号解読において、候補となる置換のペアがどれだけ妥当であるかを評価する重要な役割を果たしています。このスコアに基づいて、より良い置換の組み合わせを見つけることができます。

補足この関数は、特定の暗号方式を前提としています。
一致率が最大になったときの a と b が、正しい置換であると限りません。

回答

(*Main cryptanalysis function*)cryptanalysis[plaintext_, ciphertext_, sampleSize_ : 1000, matchThreshold_ : 0.5] := Module[{n = 26, possibleStructures, bestA, bestB, bestScore = 0, currentScore},(*Generate possible cycle structures*)possibleStructures = IntegerPartitions[n];(*Iterative sampling and scoring*)Do[Module[{a = randomPermWithStructure[RandomChoice[possibleStructures]], b = randomPermWithStructure[RandomChoice[possibleStructures]]}, currentScore = matchScore[a, b, plaintext, ciphertext];If[currentScore > bestScore, bestScore = currentScore;bestA = a;bestB = b;];], {sampleSize}];
の意味を教えてください。日本語で。

質問プロンプト

cryptanalysis 関数の解説

関数の目的
この cryptanalysis 関数は、暗号解読において、与えられた平文と暗号文から、暗号化に使用された置換 A と B を推定するアルゴリズムを実装しています。

各部分の解説
cryptanalysis[plaintext_, ciphertext_, sampleSize_ : 1000, matchThreshold_ : 0.5]:
plaintext: 平文を表すリストです。
ciphertext: 暗号文を表すリストです。
sampleSize: サンプリングの回数(デフォルト値は 1000)です。
matchThreshold: 一致率の閾値(デフォルト値は 0.5)です。

Module[{n = 26, possibleStructures, bestA, bestB, bestScore = 0, currentScore}, ...]:
Module: 局所変数を定義するための関数です。
n: アルファベットの文字数(26)です。
possibleStructures: 可能なサイクル構造を格納するリストです。
bestA, bestB: 最も良い一致率を示した置換 A と B を格納する変数です。
bestScore: 最も良い一致率を格納する変数です。
currentScore: 現在の一致率を格納する変数です。

possibleStructures = IntegerPartitions[n]:
IntegerPartitions[n]: 整数 n を複数の整数に分割するすべての方法をリストとして生成します。このリストは、可能なサイクル構造を表します。

Do[..., {sampleSize}]:
Do: 繰り返し処理を行う関数です。
sampleSize 回繰り返します。

Module[{a = randomPermWithStructure[RandomChoice[possibleStructures]], b = randomPermWithStructure[RandomChoice[possibleStructures]]}, ...]:
randomPermWithStructure: ランダムな置換を生成する関数です。
RandomChoice[possibleStructures]: 可能なサイクル構造からランダムに一つを選択します。
a, b: ランダムに生成された置換です。

currentScore = matchScore[a, b, plaintext, ciphertext]:
matchScore: 置換 a と b の一致率を計算する関数です。

If[currentScore > bestScore, bestScore = currentScore; bestA = a; bestB = b;]:
現在のスコアが最高のスコアよりも高い場合、最高のスコアと置換 A, B を更新します。

<| "BestA" -> ..., "BestB" -> ..., "BestMatchScore" -> ... |>:
辞書形式で結果を返します。

全体的な処理の流れ可能なサイクル構造を生成: アルファベットの文字数 n を分割するすべての方法を生成します。
サンプリングとスコアリング: 指定された回数 sampleSize にわたって、以下の処理を繰り返します。
ランダムな置換 a と b を生成します。
a と b の一致率を計算します。
一致率が最高のスコアよりも高い場合、最高のスコアと置換を更新します。
結果を返す: 最も高い一致率を示した置換 A, B と、その一致率を辞書形式で返します。

この関数の意味
この関数は、暗号解読において、与えられた平文と暗換文から、暗号化に使用された置換を推定するアルゴリズムを実装しています。アルゴリズムは、可能なサイクル構造をすべて試しながら、最も一致率の高い置換のペアを見つけることで、暗号を解読します。

回答


いいなと思ったら応援しよう!