2023年6月10日土曜日

AES高速化をもう少し

割と最速だったJavaで作ったAES実装もJDKのAESがOpenSSLかなにかのハードウェア実装を使うようになったおかげで数倍の差がついてしまった。KCyper-2がまだよくわからないのでAESをつついてみたりPKIの方を見たり。

Intel CPU にはAES NI というAESの計算補助的なものがあり、AMD Ryzen 2600X でも使えるようになっていて速くなる。OpenSSLが対応しているのでJavaでもOpenSSL経由でいつのまにか使えるようになっていて、高速処理ができている。

AES NIもたぶん途中の計算をまとめられるだけまとめてあらかじめ計算しておき配列に押し込んで高速化をする手法。

ソフト的にも高速化していくと同じような実装になって普通に解説されているような実装の数十倍はやくなる。

特に競ってみようというわけではないが、いろいろなハッシュや暗号を実装してみるなかでAESも乗せてみたついでに高速化もしてみたというのが前回くらい。32bitまとめるところで高速化ができたが、64bitにしてみたらもう少し速くなった気がするのでそのあたりで止めておいた。

decode側は最適化をどうやればいいのかと思っていたら、計算順を変えることでencodeと同じように最適化できることもわかったので割と高速な方にすることはできた。encodeと同じように64bit化したらencode以上に速くなった。 

AES-CBC Ryzen 7 5800X で 初期値 1400Mbps、JavaのJITが効いてくると1650Mbpsくらいまで速くなる印象。AES-NIだと初期値2500Mbpsくらいなのでかなり追いついている。AES単体だとまだまだ差は大きいが今は未計測。

元になるAESのコードが跡形もなくなってきているので、原型を留めたコードを別に残しておかないと何の参考にもならないなと。

速度比較、AES単体ではなく若干実用的なAES-CBCで比較してみることにして、JDKのコードと2倍くらいの差まで迫ることができる。ということはJDKのCBCが遅いのか。CBCで64bit演算してそのままAESに持っていくことで高速化できている感じ。JDKはそのあたりが遅い印象。

最近の主流はCBCからGCMかなんかになってきているようなので、そっちも実装したいが仕様だけ見てコード自体は見たことがなくまだよくわからず少しずつ進行中。試行錯誤中で8割くらいであとは細かい回数のテストと調整くらいかな。マルチスレッド化もJavaですぐにできる簡単なところは対応したつもりなので他はそのうち。

ガロア体の方も8ビット実装と128ビットな多バイト実装と両方作れたのでそろそろKCyper-2に手を出してもいいのかな。

PKCSとかAES.1とかABNFとかJSONとかOAuth 2.0とかJWSとかOpenID ConnectとかWeb Serverとか上から下までじわじわとフルで作っていると。

2023年1月24日火曜日

RSA鍵を作る

最近暗号系をいろいろ実装してみている中で PKCS #1 の RSA も必要になってきたので実装してみた。中身がわからないと使いにくいタイプ。

RSA は公開鍵暗号という形で秘密鍵、公開鍵の2つの鍵を使う。AESなどの共通鍵暗号とは違うところ。

公開鍵で暗号化、秘密鍵で復号ができるのがひとつめ。

秘密鍵で署名。公開鍵で検証。これが2つめ。 

公開鍵暗号共通の特徴ではなくRSAの特徴のようなので注意。

アルゴリズム的にはガロア体と同じようなものを作って2つの状態を行き来してる感じがした。

何に使えるのか。ひととおりバイト列の暗号化などにも使えるが、速さが出ないので署名用途の方が主流で暗号化も一部用途に限定して使う場合が多い。

秘密鍵と公開鍵の中身を見ていく。

RSAは大きい数の因数分解が難しいというところから作られているので2つの素数から鍵を作る。

素数(prime)2つ(pとq)を決める。2048ビットのRSAだと1024ビットくらいの素数を2つ。今なら3072ビットくらいが最低ラインになってきているので1536ビットくらいの素数を2つ。

Java で作るのでいろいろ省略できるところは省略する。

乱数はjava.math.SecureRandom っぽいところから。安全かどうかは不明。他の要素があればいろいろ混ぜるとより安全かも。普通のRandomは安全ではない。

SecureRandom srnd = SecureRandom.getInstanceStorong();

BigInteger p = BigInteger.probablePrime( len / 2, srnd );

BigInteger q = BigInteger.probablePrime( len / 2, srnd );

これで素数2つを作ってくれるのでおまかせ。素数ではない場合もあるらしい。

modulus 素数2つを掛けたもの 変数名は n など。

BigInteger n = p.multiply(q); // n = p * q

nをpとqに素因数分解するのが難しい。

次はeとdという指数(exponent)を決めていく。

eは公開指数(public exponent)、dは秘密指数(private exponent)。

e * d = 1 mod (p - 1)(q - 1) が成り立つ範囲のeとd。

e はほぼ固定値が使われていてフェルマーなんとかの 65537 ( 0x10001 ) が使われることが多い。

eの条件は、3からn-1の値、p,qと互いに素である数である。素数ではなくてもいいが奇数であること(p-1, q-1が偶数なので)。 ( 2^16 + 1 ~ 2^256 - 1 ) ぐらいが最適っぽい。

BigInteger e = BigInteger.probablePrime(17,srnd); ぐらいでいいんじゃないのかな

e が決まると上の式からdも自動的に決まる。成立しない場合は e, p, qを作り直す。

計算する場合はp-1, q-1 の最小公倍数(lambda(n))を出す必要があるらしいのでこんなかんじ。

BigInteger d = e.modInverse(lambda); // e * d = 1 (mod lambda)

lambda は p-1, q-1の最小公倍数 lambda = LCM(p-1, q-1)

最小公倍数は最大公約数から

最小公倍数 LCM(a, b) = ab / GCD(a,b);

最大公約数 GCD(a, b) = a != 0 ? GCD(b % a, a) : b;

こんなかんじ。

n と e が公開鍵、n と d が秘密鍵(最小の場合)として使われる。

OpenSSLで生成される秘密鍵にはp, qなどの要素も保存されている。

  • modulus = n
  • publicExponent = e
  • privateExponent = d
  • prime1 = p
  • prime2 = q
  • exponent1 = e.modInverse(p - 1) = d.mod(p - 1)
  • exponent2 = e.modInverse(q - 1) = d.mod(q - 1)
  • coefficient = q.modInverse(p)

各要素の使い方は省略.

メッセージ M (長さは鍵長 - 数バイトまで)、暗号文 C で簡単な計算方法

公開鍵で暗号化 C = M.modPow(e, n)

秘密鍵で復号 M = C.modPow(d, n)

秘密鍵で署名 S = Hash(M).modPow(d, n)

公開鍵で署名検証 Hash(M) = S.modPow(e, n)

HashはSHAなどJava では MessageDigest系。Paddingなどもあるので実際はちょっと違う。


 


2022年5月4日水曜日

Ryzen 7 5800X CPU変えたら爆速か?

次世代のZen 4が迫ってきてZen 3のRyzen 5000系が値下がってきたので現状のシステム構成のままでゲームに最適らしいシングルダイのRyzen  7 5800X を購入してCPU(とクーラー)だけ差し替えてみることにした。

現状の基本構成

  • AMD Ryzen 5 2600X (付属クーラー) → Ryzen 7 5800X + DEEPCOOL ASSASSIN Ⅲ
  • ASUS TUF X470 PLUS-GAMING
  • DDR4 3200? 8GBx6枚くらい所有(混合)
  • Palit GeForce RTX 2070 ?
  • Storage Transcend NVME 1TB?
  • Intel AX200 (Wi-Fi 6 + Bluetooth 5)

Zen 2直前くらいのマザーボードだがZen 3も問題なし。 PCI-Expressが3.0なのでNVME なところに影響あるかもくらい。UEFIもX5800X3D対応版が出ていたので必要ないが更新しておいたり。

Zen 2ですらないかもしれないが、メモリは高クロックまでオーバークロック対応するものを持っていたりする。CPUの影響であまり上げられなかったが。

Ryzen 7 5800X以上になると暴れもののようで発熱が多いらしく(簡易)水冷推奨でCPUクーラーがついてこない。最適なのはどのあたりかなと見てみたところ、空冷ではほぼ壊滅状態のようなので、空冷最上級らしいDEEPCOOL ASSASSIN Ⅲとやらを購入してみることにした。横から風を当てて冷やすタイプでファンも2個ついている。交換用のドライバ(物理)もついているのでお得。

水冷よりは安い、が体積がお化けでケースに収まるのかどうかわからない。メモリーと干渉するとファンがはみ出てアウト、という前提で購入。サイズはそれなりに大きい。

アップデート

もともと対応バージョンにはなっているが、事前にBIOS/UEFIをアップデートしておく。 UEFI更新だけでCPU変えてさくっと動くのはすごいところか。チップセットドライバなどは交換前でも後でも最新版にしておくのがいいかもしれない。

  • ASUS BIOS Update
  • AMD チップセットドライバ
  • Windows Update
それぞれ最新版にしておく

交換

Ryzen 5 2600X を取り外す。CPUグリスが乾いていてクーラーに張りついてすっぽ抜けてしまったがピン折れなどはなく成功?

CPUファンを外す(CPUも抜ける)、CPUファン台を外す。

CPUファン台を交換、CPUをつける、(メモリーも交換?)、CPUクーラーの配線(マザーボード)、CPUクーラーを設置、CPUクーラーにファンを2個繋げる。の順番にしないとCPUファンの電源が繋げない罠。

ASSASSINⅢはGPUを外さないとファンの取り付けが難しいが、外さないで強行。

適度に交換するものの、メモリーとASSASSINⅢのファンの位置がいろいろあったりでやはりケース蓋は閉まらず。

起動。BIOS初期設定を確認後、何の問題もなく全コア使えているようなのでOK。

メモリークロックも少し上げてみたところ、しばらくして見事に死。ディスプレイにBIOSも表示されず。マルチディスプレイだとどこにBIOSがでてくるかわからないのが難関。

1カ月ほど面倒なので放置…。

復旧

Ryzen 5 2600Xとメモリーは相性がある印象だったがRyzen 7 5800Xでも同じなのか、メモリーが悪いのか謎。

CPUをRyzen 5 2600Xに戻したりマザーボードリセット(CMOSクリア)してみるも復帰せず。外したときにCPUグリスがピンの間に…。

メモリーを引っこ抜いて安定している方のメモリ2枚差しにしてみたところ動いた。違う種類を混ぜたからか、メモリーの相性はとても大事。

Ryzen 7 5800Xに戻してクロックアップなしでしばらく安定しているのでコケたであろうメモリを別のものにして4枚差し、ASASSIN Ⅲ のCPUファンがケースファンと同じくらい巨大なので外さないとメモリが交換できない。ファンの電源を繋ぎ忘れて何度かつけたり外したり。

ベンチ

ベンチマークは3Dmark やCinebench あたりでそれっぽくなっていることを確認したが、操作自体の体感は普通。自作Java AESでの暗号の計算速度も上がっている。

Minecraft などの処理は軽くなっているので交換した意味はあるらしい。

仮想環境と Android Studio

エミュレータが動くかどうかテスト。しばらく動かしていなかったが何故か動かないので見直してみる。

  • BIOS/UEFIのアップデートでSVMが無効になっているので有効にする。
  • Windowsの[設定] [アプリ] [オプション機能][Windowsのその他の機能]で[Hyper-V]を無効にして[Windowsハイパーバイザープラットフォーム]を有効にする
  • Android StudioまたはGitHubのツールでエミュレータドライバを更新

だいたいこんな感じでエミュレータが使えるようになった

確認はコマンドプロンプトでsysteminfo を実行、

Hyper-V の要件: ハイパーバイザーが検出されました。Hyper-V に必要な機能は表示されません。

と表示されていれば準備完了。

過去BLOGに何か書いているはず

AMD Ryzen Master

Windows 11、仮想化が有効だとAMD Ryzen Masterが動かないことがあるらしい。Android Studioでエミュレータが動く設定にしてみたところ、いつのまにかAMD Ryzen Masterも動作した。パフォーマンスがそれほど必要なければECOな設定で使うと5700Xの動作と同じくらいになっていいのかもしれない。 

CCD 0の中にCCX 0がひとつしかないのでCCXまたぎの処理落ちはなくなっているはず。いろいろとパフォーマンスアップに期待。

 

2022年2月26日土曜日

GitHubのMavenあれなのでMaven Centralを使うことにした

GitHubのMaven Repositoryがあれなので、Maven Central Repositoryに登録することにしてみた。

詳細は省略してざっくりした手順。

sonatype というところが管理しているらしい sonatype OSS Repository Hosting (ossrh)というのが本当の名前か。

手順はこんな感じで案内されている。

https://central.sonatype.org/publish/publish-guide/

アカウントは以前から作ってあったので、その先から。

プロジェクトを登録する。groupId毎に申請する必要があるので別プロジェクト、サブグループなどにする場合は再度申請するらしい。SoftLib系はgroupId 1つでいいかと思うのでまだ1つしか登録はしていない。

申請はフォームがあるのでそこから申請する。

内容はURLなどと、プロジェクトの説明。

掲示板っぽくやりとりするが、機械的に処理されるので特に詳しく書く必要はない。他の人が申請しているのを見て真似してもいい。

groupId は独自ドメインの他、GitHub系も使えるが今回はドメインを持っているので使う。

GitHubのプロジェクトや独自ドメインの所有証明(DNSにTXTレコードを追加など)ができると、プロジェクトの登録は完了。

GPG(PGPのGnu版っぽいもの)の署名が必要なので、鍵と公開鍵を作ってどこかに登録する。Thunderbirdなどで使っているのあがあれば使えるのかもしれないが別で作った。GitHubにも登録しておけるかも。

事前に準備しておくのはMavenなJavaプロジェクト。

ソースコードはjavadoc までエラーなく生成できる状態になっているといい。

Mavenのpom.xml と settings.xml にossrhとGPGの鍵などを登録、ライセンスなど必要な項目も追加してdeployすると公開できる。コードのjarの他、ソースコード、javadocと各GPG署名が公開される。

gitにもGPG鍵は登録できるらしいがNetBeans IDEから更新しているので動作しているのかは不明。

リリース版は、整合性の調査など時間がかかるが数分程度で公開される。同じバージョンは1度しか公開できないし、削除もできないはず。

SNAPSHOTは同じバージョンでも繰り返し登録できる。整合性調査等もなく特に制限がなかったような気がするが、あまり使われてはいないような感じ。

数本のパッケージに分けて公開してみたが、暗号系などあと数本増やす予定もあったりなかったり。

誰か使う人が出てくるのかどうか。

https://github.com/okomeki/ にあるものの半分くらいが登録済み。SoftLib ABNF JSON を中心に更新してみたが、リリース頻度はもう少し落としてもいいのかもしれず。現状は互換性を考えず追加してみたりしているのでバージョンを固定して使ってみるのがおすすめかもしれない。JSONはほぼ固まったかなというところで暗号系とPKI系をつついてみているところ。

2021年11月7日日曜日

GitHub に Mavenリポジトリ公開してみたら失敗した

 GitHub PackagesでMavenリポジトリ?がつかえるようになっていたということで挑戦していたが、しばらくいろいろと不明でつかえなかった。

今回 GitHub Actions は使わない。非公式の方法も使わない。

https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry

日本語の説明はあるが、例がてきとーすぎて不明点が多い。

いろいろわからない部分が明確になったので、ざっくりなんとかしていくかもしれない。

完全な公開ではなく、管理にもダウンロードにもTOKENが必要なので使い道は特定のもののみで微妙。

OWNER/REPOSITORY

これは、https://github.com/okomeki/SoftLibREST の場合は OWNER が okomeki REPOSITORY が softlibrest となる。

大文字がつかえないのがまず引っかかっていたのと、REPOSITORY に何を指定していいのかわからないのでエラーの意味から何も読み取れず引っかかっていた。

OWNER は GitHub のアカウントまたは組織単位の場合は組織名(Organization)で指定する。大文字は使えないので小文字にする。

REPOSITORY は 何でも指定していいわけではなく、GitHubで使っている Repository名、かつ大文字は小文字に変えるという制約がある。サンプルが test なのでいろいろ不明だったり。

Maven では pom.xml に公開先 repository を指定する。pom.xml の artifactId とはあわせておきたいが、あわせなくてもいいかもしれない。

groupId, artifactId も仮で大文字など使っていたら小文字とハイフンぐらいに変更する。artifactId が大文字制限に引っかかっているようなので SoftLibABNF から softlib-abnf に変更してみた。

アカウントが okomeki, Repository名が SoftLibABNF、pom.xml の groupId を net.siisise、 artifactId を softlib-abnf とした場合。

次のものをpom.xml の <project>の中に追加する。 

url は OWNER/REPOSITORY

<distributionManagement>
 <repository>
  <id>github</id>
  <name>GitHub okomeki Apache Maven SoftLib Packages</name>
  <layout>default</layout>
  <url>https://maven.pkg.github.com/okomeki/softlibabnf</url>
  <releases>
   <enabled>true</enabled>
  </releases>
  <snapshots>
   <enabled>true</enabled>
  </snapshots>
 </repository>
<distributionManagement>

~/.m2/settings.xml の方に、デフォルトのprofile指定と対応するアカウントを紐づけるための serverも追加する。

<activeProfiles>
 <activeProfile>github</activeProfile>
</activeProfiles>
<servers>
  <server>
   <id>github</id>
   <username>okomeki</username>
   <password>TOKEN</password>
 </server>
</servers>

ここのTOKENは、アカウントのパスワードではなく特定の権限を持つaccess tokenというものを指定する。

作り方は GitHubの右上のアカウントアイコンから Settings を開き、左のメニューから Developer settings を開く。

Personal access tokens を開いて Generate new token で新しいトークンを発行しよう。

期限無しで発行されているものは使わないほうがよいのでつくり直すのがいい。

権限(scope)は repo の全部と write:packages, delete:packages を付けていればいいかな。

access tokenが発行されたら、それをTOKENとして使う。pom.xml の方に追加して公開してしまわないようにしよう。

依存関係はRepositoryを分けていたら個別に指定しないといけないのか?  settings.xml に追加する。

url は OWNER/REPOSITORY

<profiles>
  <profile>
    <id>github</id>
    <repository>
     <id>githubsoftlibabnf</id>
     <name>略</name>
     <url>https://maven.pkg.github.com/okomeki/softlibabnf</url>
     <layout>default</layout>
    </repository>
  </profile>
</profiles>

 こんなのでいいのかどうか。

でぷろい

あとはビルドと公開をすると、pom.xml の groupId, artifactId, version に対応するものが公開される。snapshotは上書きできるので何度でも書き直せるが、リリースバージョンを付けると上書きはできない。どうしてもという場合は削除することはできるらしい。

コマンドの場合

mvn deploy

NetBeansの場合

プロジェクトのRun maven から Goals... を開く。

Goals: に deploy

Profiles: に github (省略可)

再利用するなら Remember as: に deploy githib などと登録して

OK

GitHub の Repository を開くとそれっぽいところにそれっぽいものが増えているはず。

次回はMaven側に公開か?


 

 

2021年11月3日水曜日

Minecraft Launcher はまだ不安定

 Windows版(統合版)のMinecraftにも対応したJava EditionのLauncherがリリースされたようだが、解像度の設定などをしてみたところ、Java Edition 起動中にOSごと落ちてしまった。

Xbox系としてMicrosoft Storeからダウンロードできるが、まだ移行しない方がいいようだ。 

Minecraft 公式 https://www.minecraft.net/ja-jp/download/ からダウンロードする場合はWindows 10/11用ではなく、Windows 7/8用をダウンロードすれば従来版がつかえる。

2021年10月20日水曜日

Windows11では音系が少し変わっているらしい

Windows 11のBluetoothまわりをつついていて、ヘッドホン/イヤホンの確認をしてみたところ、変更点が2つほどあった。

同時接続

Bluetoothオーディオが複数同時接続可能になっている。1つを接続したまま、別のBluetoothオーディオデバイスを接続することができる。Windows10では通話用、オーディオ用、それぞれで1つのデバイスを切断しないと別のオーディオデバイスは接続できなかった。

音質改善

出力周波数が48kHzになっていた。Windows10ではこれがCDでしか使われない44.1kHzだったのでひっそり変更された点で間違いなさそうだ。オーディオCODECはSBC、aptXに対応していたがWindows10でAAC対応予定もあるようなのでWindows11にもAACが既に入っているので間違いないかな。[設定][システム][サウンド]からデバイスを開くと出力の設定でステレオかモノラルも選択できるようだ。左右個別の音量調節も可能。接続方式は不明。LDACにも対応するようなら96kHzにも対応していたりするかもしれないが48kHz止まりなのでLDAC採用はないようだ。

音声の劣化

48kHzと44.1kHzの違いは何かというと、44.1kHzはCDやmp3などCD由来の音源。48kHzやその倍の96kHz、192kHzはCD以外の音源でよく使われる。CDも録音時には96kHzや192kHzで収録されてから44.1kHzに落とされる場合が多い。

Windowsはハードウェアのドライバで384kHzくらいまで対応していたが、ミックス過程でどの周波数をどのように変換しているのかわからないのでどのように劣化しているかはわかりにくい。標準ドライバのBluetoothは44.1kHz固定だったので、48kHzのものはオーバーサンプリングなどしていないと44.1kHzへのミックスに困る。

おまけ デジタル再生でも外部のノイズが入る要因はいろいろある

  • 他アプリ/警告/通知/マイクなどの音が入る
  • 不可逆圧縮/展開での劣化(データ化とBluetoothなど2度圧縮される場合もある)
  • データ転送が遅延する、データ展開ループが壊れる
  • ミックスでリミッターがかかる
  • ミックス過程のデータの周波数変換
  • ケーブルのアナログ部分にデジタル回路/配線や電源からのノイズが乗る場合(ノイズ対策が弱い機器限定/CPU近辺の信号ノイズ、蛍光灯On/Offなど)
  • 電波が混雑する場合
などが該当する。

違いがわかるかどうかは、さらにヘッドホン/イヤホンと耳の性能次第。

AES高速化をもう少し

割と最速だったJavaで作ったAES実装もJDKのAESがOpenSSLかなにかのハードウェア実装を使うようになったおかげで数倍の差がついてしまった。KCyper-2がまだよくわからないのでAESをつついてみたりPKIの方を見たり。 Intel CPU にはAES NI というA...