こんにちは、Habrの親愛なる居住者! この出版物(そして、おそらく、サイクル)では、暗号化アルゴリズムの1つの実装について説明します。 なぜ実装するのですか? アイデアは新しいものではなく、アイデアが私に属していると言うことは不可能だからです。 しかし、この方法は非常に興味深いので、学ぶ価値があります。
このパートでは、アルゴリズム自体の原理と実装について簡単に説明します。
仕事の本質
このセクションでは、暗号化アルゴリズムについて説明します。 それを説明するために、いくつかの質問に答えます。
- 何を暗号化しますか? ( 入力データ )
行、またはむしろ個々のキャラクターを暗号化します。 同じ成功を収めていますが、すべての整数はコーディングに適しています。 部分的なものを暗号化することは可能ですが、コンピューターでの特殊な表現のため、一時的にそれらを削除します。
- 何を返しますか? ( 出力 )
入力文字列を処理したら、暗号化された形式で返します。 同時に、文字列のエンコードは長く、変更されていないため、非常に便利です。
内部で何が起こっているのですか? これが最も面白いです! 入力行の各文字を
基本的なセルオートマトンに送ります! なんで?
- 簡単です。 基本的なセルラオートマトンの操作アルゴリズムは、理解と実装が簡単です。
- 速いです。 私の(最も成功していない)実装でさえ、十分迅速に機能します(作業を完了することでこれを確認します)。
これはどうですか? はい、とても簡単です!
- 入力文字列を文字に分割します
- 各文字のコードは2進数に分割されます
- この1と0の文字列をセルオートマトンの分野で書きます
- 状態遷移規則を使用してセルオートマトンの進化を計算し、ある時点でフィールドの現在の状態を呼び出し元に返します
- この状態を文字コードに変換します
- 出力行の文字を「詰め込む」
文字ごとに手順2〜6を繰り返し、出力行の準備ができたら、それを返します。
実装
説明の最後にGitHubへのリンクを示します。
私のアイデアを実装するために、オブジェクト指向のC ++プログラミング言語が使用されました。 わかりやすくするために、最初の部分で強調表示されたすべてのエンティティは、個別のクラスとして実装されました。 彼らは論理名を取得しました-フィールドとルール。
クラスルール
これは、状態遷移ルールに関する情報を格納するヘルパークラスであり、ルールを操作するための関数が含まれています。
データ各インスタンスは、近傍の各ケースに従ってstd :: vectorに格納されたセル状態のみを持ちます。 なぜstd :: vectorなのか? なぜなら、このコンテナにはブール型専用の特殊化があるからです。 同時に、バイト全体ではなく、各要素に1ビットのみが割り当てられます。 このため、占有メモリの量は8倍減少します。
機能- コンストラクター。 入力は、size_t型の符号なし整数です。 この番号は、数値セグメント[0; 255]に属しているかどうかがチェックされます。 テストが成功すると、バイナリビットに分割され、bool型の内部ベクトルに格納されます。 それ以外の場合、out_of_range例外がスローされます。
- インデックス演算子。 size_t型の符号なし整数を取ります。 数値が数値セグメント[0; 7]にある場合、指定されたインデックスにあるbool型のベクトルの要素が返されます。 それ以外の場合は、out_of_range例外を再度スローします。 この数値は、セルの近傍です。 この近傍では、遷移ルールは将来の世代の中央のセルの状態を比較します。
このクラスは使いやすく、理解しやすいです。 しかし、ここに議論のトピックがあります。 Fieldクラスのインスタンスと組み合わせてのみ使用されるため、内部にしないのはなぜですか? この質問に対する明確な答えはありません。 そして本当に、なぜですか? オブジェクトを必要に応じて構築できるように、プライベートにすることができます。 それは魅力的ですが、現時点では非常に独立していると思います。 結局、いくつかの個別の移行ルールを事前定義し、異なる暗号化方法を必要とする文字列をエンコードすることができます。 この便利さをプログラマから奪いたくないので、私の実装では、RuleタイプはFieldタイプとは別に宣言されます。
フィールドクラス
これは、コーディングを直接実行する関数が定義されるメインタイプです。
データ- 状態遷移規則。 状態遷移規則を保持するRuleクラスのインスタンス。 クラスインターフェイスについては上記で説明しています。
- フィールドの現在の状態。 フィールド内のすべてのセルの現在の状態を格納するstd :: vector <bool>クラスのインスタンス。 ベクトルは、コンストラクターでエンコードされた文字のバイナリビットで初期化され、エンコードが行われる演算子()が呼び出されると変更されます。
- 補助フィールド。 フィールド内のすべてのセルの状態を格納するstd :: vector <bool>クラスのヘルパーインスタンス。 次世代のセルの計算に使用されます。 演算子()で直接定義することも可能ですが、この演算子は非常に頻繁に使用されるため、ベクトルを個別に定義する方が実用的です。
- フィールドのサイズ。 ASCIIエンコードのみが現在サポートされているため、セルラーオートマトンのフィールドのサイズを格納するsize_t型の定数は8です。
機能- コンストラクター。 Rule型のオブジェクトとunsigned char型の定数への定数参照を受け入れます。 Ruleクラスのコンストラクターは明示的に宣言されていないため、リンクの代わりに整数を渡すことができます。これは、Wolframコードの形式で記述された遷移ルールの番号です(冒頭のリンクを参照)。 送信された文字はバイナリフィールドに分割され、フィールドの現在の状態を格納するベクトルに順番に書き込まれます。
- 演算子()。 ここで文字エンコードが行われます。 次世代が計算されます(各セルについて、その近傍を調べ、遷移ルールを使用して、次世代の中間のセルの状態を見つけます)。 フィールドはリングで閉じられているため、フィールドの端にあるセルの状態を個別に考慮します。 その後、フィールドは10進数に変換され、文字コードが取得され、関数から返されます。
いくつかのテスト
以下のリンクでプログラムの操作性を自分で確認できます。 ここで、パフォーマンスに関して私にとって興味深いと思われるいくつかの事実を説明します。 覚えておいてください、彼らはこのプログラムだけを特徴づけますが、決してアルゴリズム自体を特徴づけません。 さあ始めましょう!
ルール110を使用してすべてのUnicode文字を暗号化するには、システム上で645,000ティック、つまり約0.645秒(10開始の平均値)かかりました。
ルール110を使用して単一のUnicode文字を暗号化するには、80ティック、つまり約0.00008秒(10開始の平均値)かかりました。
256個すべてのルールを使用するすべてのUnicode文字は、133500000ティックまたは約134秒(10回の開始の平均値)で暗号化されました。
しかし、最も奇妙なことは、正しい結果が発行されることです! 手動でチェックし、いくつかの数字を個人的に暗号化します。
おわりに
私の意見では、 それは非常によくはっきりと判明しました 。 間違いから逃れることはできませんが、罪がないわけではありません。 実装は正しく機能し、その仕事をします。 もちろん、それを使用するのはまだ初期段階であり、多くは完全には実現されていませんが、私はあなたに考えの糧を与えました。