Towards Securing the Internet of Things with QUIC を読んでみました。
https://www.easychair.org/publications/preprint/68D2
preprintバージョンのため今後更新される可能性はありそうです。
Linuxが載らないような(RAM256KB、フラッシュメモリ1MB)デバイスで、quanのコードサイズ、スタックとヒープの使用量、1-RTTと0-RTT接続を使った場合のバッテリー消費量などを比較しています。
もう少し詳細に紹介します。
本論文では、Linuxが載らないようなリソースが制限されたIoTデバイスでQUICが実行できるかどうかのフィジビリティ検証を行っています。
具体的には、Particle Argonというデバイスと、ESP32-DevKitC V4 (以下ESP32) というデバイスの二つで検証を行っています。
前者は256KBのRAMと1MBのフラッシュメモリ、後者は520KBのRAMと4MBのフラッシュメモリを持っています。
詳細なスペックは以下の通りです。
実装
QUICの実装にはQuant を使っています。ネットワークスタックにはWarpcore を使用しています。
また、暗号化関連では、picotls、micro-ecc、cifra、といったライブラリに依存しています。
ArgonとESP32はそれぞれTLS1.3で必要な機能のハードウェア実装を持っていますが、アプリケーション用には提供されていません。またpicotlsもそれらを使うための機能は持っていないため今回は使われていません。
検証
検証はバイナリサイズ、スタックサイズとヒープサイズ、電力消費とパフォーマンスの3つの観点で行われています。
バイナリサイズ
ここでは、5KBのデータをダウンロードするという最小のアプリケーションに対して必要なバイナリサイズを調べています。
図は、ArgonとESP32それぞれに対して、ビルド時の最適化を段階的に加えていったバイナリサイズになります。
ベースラインはそれぞれ98KBになっています。
only 32bit
では、64ビットの操作を消しています。ここでは64bitの割り算がなくなる影響が大きいらしいです。また、packet number、window size、 RTTの計測に関わる部分もバイナリの削減に寄与しています。
only client
では、デフォルトでQuantに含まれるサーバー機能を削減しています。ここでは特にTLSの部分で11~14KBの削減に成功しています。QUICレイヤーでは、長さ0のコネクションIDを使うことで、IDのルックアップに関連するデータ構造を削除できることがサイズの削減に寄与しています。
min cipher
では、暗号化で使う機能を減らしています。TLS1.3は、AES_128_GCM_SHA256はMUSTで実装する必要がありますが、AES_256_GCM_SHA384やCHACHA20_POLY1305_SHA256はMUSTではありません。同様に、鍵交換はsecp256r1がMUSTですが、X25519はMUSTではありません。IoT向けの最小のサブセットとして、AES_256_GCM_SHA384とsecp256r1 を使うようにしました。これによって、7~8KB削減に成功しています。もし、Device OSやRIOTがハードウェアの機能を使えるなら、cifra、 micro-eccは全部ドロップできるので、それぞれ5KB、 4KBの削減が可能になります。
ここまでの取り組みで、バイナリサイズをそれぞれ、25、30%削減することができました。
ここからさらにQUICの機能をあきらめることで、さらにサイズを削減できます。ただし、それらによる効果はここまでのものほど大きくはなさそうです。
connection migration
は インターフェースの対応に変更するコネクションマイグレーションを削減しています。想定ユースケースのMulti-homedやlong-lived clientはどちらもIoTのユースケースには必要ないためです。その結果、3KBが削減されます。
W/O err reasons
では、CONECTION_CLOSEのエラー文字列を削除します。そうすると静的な文字列がなくなるため1-2KB削減されます。
w/o SR support
ではステートレスリセットの機能を削減します。これによって、1KBサイズを削減します。
デフォルトだと、Quantはピアからの再送を避けるために、順番外で来たSTREAMフレームとCRYPTOフレームをキャッシュします。しかしキャッシュのためのデータ構造がサイズを食うためそれを削除します。0-RTTデータのreorder機能を削減すると1KB(drop reor 0-RTT
)、すべてのreorderデータを削減することで1KB(drop all reorder
) のサイズ削減につながります。
最後に、w/o info
では、LinuxのTCP_INFOのように接続の統計情報を集める機能を削除します。これによって1KBの削減ができます。
これらのバイナリサイズ削減を結果、QUICに必要なバイナリサイズは、Argonでは63KB、ESP32では58KBのになりました。これは、ベースラインと比較するとそれぞれ、36%、40%の削減された結果になります。
スタックとヒープサイズ
ここでは5KBのオブジェクトをダウンロードするユースケースにおけるスタックとヒープの使用量を調べています。
計測は、-finstrument-functions
を使って、関数に入ったときと出た時にヒープ、スタック、コールスタックの深さをシリアル経由で保存しています。ただし、112.5Kbit/sのシリアルのリンクでのロギングになるため、cifra、 micro-eccについては調査していません。
そのため、必要となる最大のスタック・ヒープサイズの計測はできていませんが、動作中のスタックとヒープサイズ推移や暗号化がハードウェアにオフロードされたときの使用量について知ることができます。
計測結果の図は以下のようになります
図では、4つのフェーズを決めています。
init phase
ではQuantとWarpcoreの初期化を行います。
Open phase
ではQUICの接続を確立します。
Transpher phase
では、リクエストを送って、5KBのレスポンスを受け取ります。
Close Phase
では、QUICの接続を閉じて、リソースを開放します。
スタックサイズは、Argon、 ESP32ともに似た傾向がみられます。両者ともにopen phase
では3KBを占めることがあり、transfer phase
では1KB程度の使用量になっています。
TLS handshakeの公開鍵暗号化のほうが、共通鍵暗号化よりもスタック使用量が多いことが理由として考えられます。 最大サイズの3KBのスタック利用量はリソースの制限があるデバイスでは多いと考えられます。この多くは、picotlsが確保している静的なバッファが原因のようです。
ヒープサイズは、両方ともフラットという結果になっています。この挙動はリソースが制限されているノードでは望ましい挙動になります。
こうなる理由はQuantがinit phase
で、メモリを確保しているからのようです。Figure 3. ではその状態をわかりやすく見ることができます。init phase
で23KB使用量が増えています。これは、15MTUサイズのパケットバッファーと、8バイトのエンコードデコードの情報とかほかのグローバルデータのために使われています。
Energy and Performance
ここでは電力消費量と性能の計測を行っています。ESP32には適切なバッテリーがないため、Argonで評価を行っています。
計測には26,640J確保できる 200mAh 3.7VのLiPoバッテリーを使用しています。
今回の実験では、5KBのオブジェクトのリクエストを連続して行います。(単一接続ではなく、接続、取得、切断を繰り返しています。)
すべて1-RTT handshakeで計測したものと、もう片方は1回目だけ1-RTTで、あと残りは0-RTTで計測したものの2種類の計測を行っています。
すべて1-RTTで計測した場合は、29338回実行できています。1回あたりのエネルギー消費量は0.90Jです。
初回のみ1-RTTで接続しそれ以降は0-RTTで接続する場合、31844回(1回あたりのエネルギー消費量は0.83J) となっています。
Argonのバッテリーレベルのレポートがそこまで正確ではないようなので、最初の充電量が多かったのか実際に0-RTTの消費量が少なかったのかまではまだわかっていないとのことです。