なぜ WebAssembly 生成を Go にしたのか

V
Nov 15, 2020

オンラインイベントで聞かれて、ツイッターにつぶやいたら思った以上に反響があったので、もう少し詳細に書いてみます。

思ったより反響があった

まとめ

  • 信頼できる暗号ライブラリがある
  • 自分が TypeScript より Go のほうが書ける
  • Go の Wasm バイナリサイズを気にする必要がない

WebCrypto にない暗号が必要

自社の WebRTC SFU において End to End Encryption (E2EE) をブラウザ上で実現するためにはいくつかの壁がありました。

一つは WebCrypto が提供していない暗号を利用したいというものです。

今回 E2EE を実装するにあたり採用した Signal プロトコルでは公開鍵暗号に Curve25519 を採用しています。残念ながら WebCrypto では Curve25519 に対応していません。この時点で「暗号ライブラリをどこからもってくる」というのが必要になりました。

一つ思いついたのが Emscripten を利用した何かしらの信頼できる暗号ライブラリを引っ張ってくるということです。libsodium あたりを利用するというのも一瞬考えましたが、Curve25519 を使うだけにしてはオーバキルだと判断しました。

ただそれはそれで JavaScript 側で Signal プロトコルを実装するということになり、しんどそうだなと判断しました。

そこで考えたのが Go です。Go の暗号ライブラリは Go で書かれています。一部 CPU 専用命令が有効になるのもあります、それを使わず Wasm 化は可能でした。

Go の暗号ライブラリは「標準」で用意されているもののため信頼性がとても高いです。そのためこのライブラリをそのまま Wasm 化できるのはとても大きいと判断しました。

どうでもいいですがプロトコル実装者には暗号ライブラリを自作するのは学習以外ではやってはならぬという鉄の掟が存在します。

Signal プロトコルを TypeScript で実装したくなかった

Go の暗号ライブラリを使うと判断したタイミングで Wasm 側で Signal プロトコルの状態管理までしたいと考えていました。

Signal プロトコルはシンプルではありますが、状態を管理するものが多いため、可能な限り Go で書いて、テストをガッツリ書いておきたいと考えたからです。

また自分が TypeScript で Signal プロトコルを実装できる能力がないと判断したというのもあります。

実際 Go で状態管理は思った以上によく書けました。テストもガッツリ書いたおかげでミスも減りました。

JavaScript と Go のグルー部分は自分ではなく JavaScript に慣れている社員に書いてもらいました。

Go の生成した Wasm バイナリサイズを気にする必要がない

WebRTC SFU で利用するため、2.6 MiB (圧縮して 700KiB) のバイナリは正直全く気にならないレベルです。E2EE 自体が CPU を食べますし、音声と映像を送受信するだけで 2.6MiB なんて一瞬です。

容量を気にする必要がないというのも大きな判断材料になりました。

雑感

信頼できる暗号ライブラリと慣れている言語での状態管理実装はとてもマッチしました。コード自体もとても短く書けて、テストも充実させられることができました。

今回のような暗号ライブラリの利用とプロトコルの詰め込みという天で WebAssembly を利用する場合は C/C++ か Rust が本命だと思いますが、今回は Go を採用したことで暗号ライブラリをサクッと利用でき、状態管理もさくっと実装できました。

今後は Wasm 側のテストも Go で chromedp を利用して書いていければと考えています。

今回は用途にピッタリハマったから良いと思いますが、Go での Wasm 生成は何かしら明確な理由がない限りは選択するのはおすすめできません。

適材適所です、ほんとに。

ちなみに Sora Labo にて WebAssembly を利用した E2EE のサンプル、E2EE (WebAssembly 版) マルチストリームが試せますのでもしよければどうぞ。

おまけ

Twitter でツッコミいただいたので、せっかくだから TinyGo で試してみたらビルドはできました。動かすために wasm_exec.js を TinyGo のものに変更してみましたが、残念ながら “syscall/js.finalizeRef not implemented” というエラーがでて動きませんでした。どこかで追いかけようと思います。もしこれを読んでなにかヒント持ってる方は是非コメントください。

追記

--

--