第36章. バイトコードと署名付きバイトコードの読み込み
この章の目的
この章を読み終える頃には、事前にコンパイルされたバイトコードを読み込み、信頼マトリクスに対して署名付きバイトコードを読み込み、そしてトラストスキップコンストラクタを理解しているはずです。この章を読み終える頃には、事前にコンパイルされたバイトコードを読み込み、信頼マトリクスに対して署名付きバイトコードを読み込み、そしてトラストスキップコンストラクタを理解しているはずです。
事前にコンパイルされたバイトコードを読み込む
keleusma compileやビルドパイプラインから出てきた.kel.binファイルをホストが持っている場合、字句解析、構文解析、コンパイルの各段階を飛ばせます。keleusma compileやビルドパイプラインから出てきた.kel.binファイルをホストが持っている場合、字句解析、構文解析、コンパイルの各段階を飛ばせます。
#![allow(unused)]
fn main() {
let bytes = std::fs::read("script.kel.bin")?;
let mut vm = Vm::load_bytes(&bytes, &arena)?;
}
Vm::load_bytesはワイヤフォーマットのフレーミングを検証し、構造検証を行い、資源境界検証を行って、VMを返します。フレーミングの失敗はVmError::LoadError、解析の失敗はVmError::VerifyErrorです。検証はソースからコンパイルされたモジュールに対するものと同じです。バイトコードの読み込みは安全性のチェックを飛ばすわけではなく、コンパイルを飛ばすだけです。Vm::load_bytesはワイヤフォーマットのフレーミングを検証し、構造検証を行い、資源境界検証を行って、VMを返します。フレーミングの失敗はVmError::LoadError、解析の失敗はVmError::VerifyErrorです。検証はソースからコンパイルされたモジュールに対するものと同じです。バイトコードの読み込みは安全性のチェックを飛ばすわけではなく、コンパイルを飛ばすだけです。
署名付きバイトコードを読み込む
signedのエントリー関数からコンパイルされたモジュールはFLAG_REQUIRES_SIGNATUREビットを運び、Vm::load_bytesはそれを拒否して、署名付きの経路に呼び出し側を案内します。署名付きモジュールはVm::load_signed_bytesで読み込みます。これは信頼する公開鍵のスライスを取ります。signedのエントリー関数からコンパイルされたモジュールはFLAG_REQUIRES_SIGNATUREビットを運び、Vm::load_bytesはそれを拒否して、署名付きの経路に呼び出し側を案内します。署名付きモジュールはVm::load_signed_bytesで読み込みます。これは信頼する公開鍵のスライスを取ります。
#![allow(unused)]
fn main() {
let pub_bytes: [u8; 32] = std::fs::read("pub.bin")?.try_into().unwrap();
let key = ed25519_dalek::VerifyingKey::from_bytes(&pub_bytes)?;
let mut vm = Vm::load_signed_bytes(&signed_bytes, &arena, &[key])?;
}
このスライスが信頼マトリクスです。モジュールは、署名がスライス内のどれかの鍵に対して通れば読み込まれます。空のスライスはすべての署名付きモジュールを拒否します。マトリクスは構築されたVMにコピーされるので、その後の署名付きホットスワップ読み込みも同じ鍵を継承します。このスライスが信頼マトリクスです。モジュールは、署名がスライス内のどれかの鍵に対して通れば読み込まれます。空のスライスはすべての署名付きモジュールを拒否します。マトリクスは構築されたVMにコピーされるので、その後の署名付きホットスワップ読み込みも同じ鍵を継承します。
署名されていないベースラインから起動して、その後だけ署名付きの更新を受け入れるホストは、構築のあとに鍵を登録します。署名されていないベースラインから起動して、その後だけ署名付きの更新を受け入れるホストは、構築のあとに鍵を登録します。
#![allow(unused)]
fn main() {
let mut vm = Vm::new(unsigned_baseline_module, &arena)?;
vm.register_verifying_key(operator_key);
}
トラストスキップコンストラクタ
Vm::new_uncheckedは資源境界検証を飛ばします。実行ループはメモリ安全のために構造検証に依存しているので、構造検証は依然として走ります。Vm::new_uncheckedは資源境界検証を飛ばします。実行ループはメモリ安全のために構造検証に依存しているので、構造検証は依然として走ります。
#![allow(unused)]
fn main() {
let vm = unsafe { Vm::new_unchecked(module, &arena) };
}
unsafeが付いているのは信頼契約を表すためです — 呼び出し側は、バイトコードの資源境界が以前にビルド時に検証されたことを誓います。意図される用途は、1回検証してバイトコードを配布し、毎回の読み込みで再検証しなくて済むビルドパイプラインです。安全な検証器が却下するプログラムを通すために使うのは、言語の保証の外側での意図的な誤用で、そう文書化されています。第5部の有界な時間とメモリの保証は、Vm::newの下では成り立ち、Vm::new_uncheckedの下ではホストの誓いに弱まります。unsafeが付いているのは信頼契約を表すためです — 呼び出し側は、バイトコードの資源境界が以前にビルド時に検証されたことを誓います。意図される用途は、1回検証してバイトコードを配布し、毎回の読み込みで再検証しなくて済むビルドパイプラインです。安全な検証器が却下するプログラムを通すために使うのは、言語の保証の外側での意図的な誤用で、そう文書化されています。第5部の有界な時間とメモリの保証は、Vm::newの下では成り立ち、Vm::new_uncheckedの下ではホストの誓いに弱まります。
この章のまとめ
Vm::load_bytesは事前にコンパイルされた.kel.binを読み込み、ソースからコンパイルされたモジュールと同じく検証します。Vm::load_bytesは事前にコンパイルされた.kel.binを読み込み、ソースからコンパイルされたモジュールと同じく検証します。Vm::load_signed_bytesは信頼する公開鍵のスライスに対して署名付きバイトコードを読み込みます。Vm::load_signed_bytesは信頼する公開鍵のスライスに対して署名付きバイトコードを読み込みます。register_verifying_keyは構築後のVMに鍵を加えます。Vm::new_uncheckedは、明示的なunsafeの信頼契約のもとで、資源境界チェックを飛ばします。Vm::new_uncheckedは、明示的なunsafeの信頼契約のもとで、資源境界チェックを飛ばします。
次の章では走っているモジュールを新しいものに置き換えます。