さわって動かせる「エニグマ」公開してみた

:::note warn
Web プログラミングは**ガチの素人**なので多少のガバはご容赦ください。
:::

# TL;DR
https://reika727.github.io/enigmaISimulator/

こんなん作りました。最後に打った文字 "G" が "O" へ暗号化されているのが見えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507500/b1ed4ae1-7a57-e51c-8ba5-331422519d24.png)
そしてひらがな対応版も作ってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507500/26b38b30-158d-b4da-8cce-ab3270c08a21.png)
サイト自体のソースコードは[こちら](https://github.com/reika727/reika727.github.io)です。

# エニグマとは
エニグマは第二次世界大戦期にドイツが使用していた暗号機です。エニグマの詳細についてはすでに[素晴らしい記事](https://qiita.com/opengl-8080/items/995778d1cce43ed5babc)があるので割愛します。

:::note info
上記記事でもおススメされていますが、サイモン・シン「暗号解読」はガチで名著です。皆さん読んでください。
:::

# 技術的詳細

## エニグマの実装

今回は JavaScript よりも型安全であるとされる **TypeScript** を使って[実装しました](https://github.com/reika727/reika727.github.io/blob/main/src/enigmaISimulator/enigma.ts)。

ただここで問題になってくるのが、**本当に正しく実装できてるのか**わからんということです。そこで史実で実際に用いられた暗号文の情報がないか調べてみたのですが、うってつけのものを見つけました。

https://www.bytereef.org/m4_project.html

終戦後も未解読のままだった暗号を分散コンピューティングによって解読していたプロジェクトです。このプロジェクトと一致する解読結果が出てくるか **Jest** を使ってテストしてみました。たとえば[最初に解読された暗号](https://www.bytereef.org/m4-project-first-break.html)と同じ結果になることを確かめるテストはこんな感じになります。

```typescript
test('M4 FIRST BROKEN MESSAGE', () => {
    expect(
        new M4(
            new PlugBoard(Alphabet.capitalLatin, ['A', 'T'], ['B', 'L'], ['D', 'F'], ['G', 'J'], ['H', 'M'], ['N', 'W'], ['O', 'P'], ['Q', 'Y'], ['R', 'Z'], ['V', 'X']),
            M4.rotorI,
            M4.rotorIV,
            M4.rotorII,
            M4.rotorBeta,
            M4.reflectorB,
            'VAAA',
            'ANJV'
        ).decrypt(
            'NCZWVUSXPNYMINHZXMQXSFWXWLKJAHSHNMCOCCAKUQPMKCSMHKSEINJUSBLKIOSXCKUBHMLLXCSJUSRRDVKOHULXWCCBGVLIYXEOAHXRHKKFVDREWEZLXOBAFGYUJQUKGRTVUKAMEURBVEKSUHHVOYHABCJWMAKLFKLMYFVNRIZRVVRTKOFDANJMOLBGFFLEOPRGTFLVRHOWOPBEKVWMUQFMPWPARMFHAGKXIIBG'
        )
    ).toBe(
        'VONVONJLOOKSJHFFTTTEINSEINSDREIZWOYYQNNSNEUNINHALTXXBEIANGRIFFUNTERWASSERGEDRUECKTYWABOSXLETZTERGEGNERSTANDNULACHTDREINULUHRMARQUANTONJOTANEUNACHTSEYHSDREIYZWOZWONULGRADYACHTSMYSTOSSENACHXEKNSVIERMBFAELLTYNNNNNNOOOVIERYSICHTEINSNULL'
    );
});
```

そしてテスト結果がこちらです。

```
$ npm run test

> reika727.github.io@1.0.0 test
> jest

 PASS  __test__/enigma.test.ts (11.695 s)
  ✓ M4 FIRST BROKEN MESSAGE (30 ms)
  ✓ M4 SECOND BROKEN MESSAGE (12 ms)
  ✓ M4 FINAL BROKEN MESSAGE (14 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        12.132 s, estimated 17 s
Ran all test suites.
```

どうやらちゃんと実装できてそうです👍

## UI の作成
一番大変だったのがここです。世の中には **Vue** とか **React** とか **Angular** とか便利なフレームワークがあるようですが、選択肢が多すぎてどれを使えばいいのかわからなかった~~ついでに使い方もよくわからなかった~~ので、生のスクリプトから DOM を直接弄るという昔ながら（？）の方法で動かしました。また、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507500/f917d879-e4f5-c9e1-79e1-a812bdf0c688.png)
この、canvas 上にエニグマを描画するところなんか**丸**とか**線**とかの部品一個一個を描画しなければならないので、必然的にコードがめっちゃ長くなってしまいます。こういうものをもっと楽に描画できる方法や、もっとスマートに UI を作る方法をご存知の方はぜひご教示ください・・・

## TypeScript を用いたサイトの作り方

残念ながら現時点では TypeScript を HTML に埋め込むことはできないので、JavaScript へのトランスパイルが必要になります。これには **webpack** と **ts-loader** と **HtmlWebpackPlugin** というパッケージを組み合わせることで実現できます。まずソースコードがこんな感じの構成になっているとします。

```
project-root/
  └ src/
      ├ index.html
      ├ index.ts
      └ module.ts
```

ここで注目すべきなのは、index.html は index.ts を読み込んで**いない**ということです。つまり `<script src="index.ts"></script>` とかは書かれていません（先ほども言ったように HTML に TypeScript を埋め込むことはできないので）。

ここで webpack, ts-loader, HtmlWebpackPlugin を使います。webpack は JavaScript を一つにまとめたり CSS を一つにまとめたりすることができます。今回は index.ts と module.ts をまとめて一つのファイルにするのに使います。しかし webpack 単体では JavaScript しか扱えないので、TypeScript を読み込ませるために ts-loader を組み合わせるわけです。このようにして index.ts と module.ts をひとまとめにした **main.js** が自動生成されます。

```
project-root/
  ├ src/
  │   ├ index.html
  │   ├ index.ts
  │   └ module.ts
  └ dist/
       └ main.js
```

さらに HtmlWebPackPlugin を組み合わせることで、main.js を読み込む index.html を dist/ 配下に自動生成してくれます。最終的にはこのようになります。

```
project-root/
  ├ src/
  │   ├ index.html
  │   ├ index.ts
  │   └ module.ts
  └ dist/
       ├ index.html <- main.js を読み込むコードが自動で追加されている
       └ main.js
```

この dist/ を実際に Web 上に公開すればよいわけです。

## ホスティング
作成したページは GitHub Pages で公開しました。また GitHub Actions を使うことで、先ほども出てきた Jest を使ったテストや TypeScript から JavaScript へのトランスパイルなども push のたびに自動で行うようにすることができます。便利ですね～。

# 今後の課題
- UI フレームワークの選び方と使い方を覚える
- もっと<font color=#55C500><b>オシャンティー</b></font>な Web デザインの作り方を勉強する