**データ構造を誤った方法で署名する**

2026/04/02 4:52

**データ構造を誤った方法で署名する**

RSS: https://news.ycombinator.com/rss

要約

日本語訳:

Snowpackは、暗号操作中に異なるデータ型が互いに誤って解釈されることを防ぎ、代替攻撃を抑止するプロトコルレベルのドメインセパレーターを導入します。
各タグ付き構造体について、コンパイラはコンパイル時に一度だけランダム64ビット値を生成し、IDLに埋め込みます。このセパレーターはプロトコルの寿命全体で一定である必要があり、そのユニーク性はコンパイラ/実行時に検証され、重複が見つかるとパニックまたはエラーになります。セパレーターは最終的なシリアライズ形式には含まれません;代わりに署名・検証・暗号化・ハッシュ化・HMACの前にオブジェクトのバイトストリームと連結されます。セパレーターが正規化されたシリアル化に含まれていないため、ある型用に作成された署名は、同じバイトストリームを共有する別の型には失敗します。

Snowpack のエンコーディングは JSON スタイルの位置配列を使用してフィールド順序を保持し、欠損フィールドには

nil
を挿入して後方/前方互換性をサポートします。中間配列は厳格な制約下で正規化 MsgPack バイトストリームにシリアライズされます:整数サイズの最小化と 1 ペア以上のキー・バリュー対を持つ辞書を禁止し、決定的な出力を保証します。リストは配列としてエンコードされ、オプション値は単一ペアの辞書に変換されます。タグ付きユニオン(variant)は配列または単一キーの辞書のいずれかを使用し、この形式は既存の MsgPack ライブラリと完全に互換性があります。

このシステムは GitHub 上でオープンソース化されており、現在は Go と TypeScript のターゲットをサポートしています。将来的には他の言語も追加予定です。クロスタイプ代替脆弱性を排除することで、Snowpack は安全なシリアライゼーションに依存する任意のアプリケーションを強化します。その設計は、ドメイン分離と正規化エンコーディングを提供するために他のシリアライゼーション方式にも採用できます。

本文

暗号アルゴリズムに入力する前にデータをどのようにパッケージ化しますか?
(署名、暗号化、MAC あるいはハッシュ)

この質問は数十年もの間、十分な解決策が得られずに残ってきました。

対処すべき重要な課題は少なくとも2つあります:

  1. 正規化された出力 – エンコーディングは必ず同一の「カノニカル」出力を生成する必要があります。Bitcoin のようなシステムでは、異なるエンコーディングが同じメモリ上のデータにデコードされるケースで問題が発生しています。
  2. ドメイン分離 – エンコーディング体系は「ドメイン分離」の重要性を確実に扱う必要があります。

問題例

次のような IDL(ここでは protobuf を想定)を考えてみます。

message TreeRoot {
  int64 timestamp = 1;
  bytes hash      = 2;
}

message KeyRevoke {
  int64 timestamp            = 1;
  publicKeyFingerprint hash = 2;
}

この2つの構造体はフィールドごとに完全に揃っていますが、意味する内容は全く異なります。
あるノードが

TreeRoot
を署名し、その署名をネットワークへ送信したとします。攻撃者は、バイト列ごとに同一になる
KeyRevoke
メッセージを作成し、そこに
TreeRoot
の署名を貼り付けることができます。
結果として、実際には
KeyRevoke
を署名したかのように見せかけることが可能になります。

これは理論上の攻撃ではなく、Bitcoin、Ethereum 上の DEX、TLS、JWT、AWS などで長い歴史を持つ問題です。MAC(HMAC や SHA‑3)、ハッシュ、あるいは暗号化に対しても同じ考えが当てはまります――現代の多くの暗号化手法は認証付きです。一般的に、暗号技術は送信者と受信者がペイロードだけでなく「データ型」についても合意していることを保証すべきです。

既存の解決策では、Solana のローカル名ハッシュや Ethereum でのベストプラクティス、TLS v1.3 の「コンテキスト文字列」など、アドホックな手法が使われています。より体系的なアプローチが求められます。


FOKS のアイデア:IDL 内にドメインセパレータを埋め込む

FOKS は Snowpack と呼ばれる計画を発案しました。これはランダムで不変のドメインセパレータを IDL に直接埋め込みます。

struct TreeRoot @0x92880d38b74de9fb {
  timestamp @0 : Uint;
  hash      @1 : Blob;
}

簡易コンパイラが IDL を対象言語へ変換します。
その言語では、ランタイムライブラリが次のようなメソッドを提供します:
ドメインセパレータ(

@0x92880d38b74de9fb
)とオブジェクトのシリアライズ結果を連結し、そのバイト列を署名原語へ渡す。検証側は同じ連結を再構築して署名を確認します。

ドメインセパレータ自体は最終的なシリアリゼーションには現れません。
送信者と受信者は共有プロトコル仕様でこの値に合意するため、余計なバイトを浪費しません。暗号化、HMAC、ハッシュも同様の手順で機能します。

Go(また TypeScript など)では型システムがセキュリティ保証を強制します。

func (t TreeRoot) GetUniqueTypeID() uint64 { return 0x92880d38b74de9fb }

func Sign(key Key, obj VerifiableObjecter) ([]byte, error)
func Verify(key Key, sig []byte, obj VerifiableObjecter) error

VerifiableObjecter
GetUniqueTypeID()
EncodeToBytes
などを要求するインタフェースです。
ドメインセパレータを持たない構造体は
GetUniqueTypeID()
を実装できず、
Sign
Verify
に渡すことが型エラーで拒否されます。同様に暗号化・MAC でも同じルールが適用されます。

ランダムに生成されたドメインセパレータはほぼ確実にユニーク(グローバル)であるため、送信者と検証者が扱うデータ型を誤解することはありません。先述の代替攻撃も検証失敗に終わります。

開発者は IDE や CLI などの簡易ツールを使ってランダムドメインセパレータを生成し、プロトコル仕様へ挿入すればよいでしょう。


ランダム生成ロジック

生成ロジックは Rabin フィンガープリントで多項式を乱数化する手法に似ています。
Bob が新しいプロジェクトのために全てのドメインセパレータをランダムに生成した場合、確率的には Bob の検証者が別プロジェクトから来た署名を受け入れることはほぼ起こりません。

Mallory が Bob の公開仕様を見て新規プロジェクトを作り、同じドメインセパレータを意図的に再利用したとしても、彼女が Bob の秘密鍵を持っていなければ Bob で署名が受理されることはありません。
Mallory がランダムに生成しても保証は変わりません。

Snowpack コンパイラとランタイムはプロジェクト内で全ドメインセパレータのユニーク性を確認し、重複があればエラーまたは panic を発生させます。

ドメインセパレータはプロトコルの寿命にわたって固定しておくべきです。フィールド追加・削除時も、残存フィールドの位置が変わらず、退役したフィールドを再利用しない限り問題ありません(protobuf や Cap’n Proto と同様)。


Snowpack IDL:ドメイン分離 + カノニカルエンコーディング

Snowpack の組み込みドメイン分離は革新的です。さらに RPC および暗号関数への入力シリアリゼーションに対して、前方・後方互換性のある簡易かつ効果的な体系を提供します。

エンコーディングフロー

  1. Go 構造体 → Snowpack – コンパイル時生成
  2. Snowpack → 途中 JSON‑似オブジェクト – 自己記述配列(例:
    [1234567890, \xdeadbeef]
  3. 途中オブジェクト → バイト列 – MsgPack を使用し、以下の制約付き
    • 整数は最小サイズエンコードのみ
    • 複数キー–バリュー対を持つ辞書は送信されない(カノニカルキー順序の問題回避)

結果として毎回同一にエンコードされたフラットなバイトストリームが得られます。

プロトコル進化例

struct TreeRoot @0x92880d38b74de9fb {
  hash          @1 : Blob;
  timestampMsec @2 : Uint;
}

中間エンコードは次のようになります:

[ nil, \xdeadbeef, 1234567890123 ]

古いデコーダは欠損フィールドを

nil
と解釈し、新しいデコーダは新フィールドに対してゼロ値を受け取ります。プロトコルレベルでの失敗は起こりません。


追加機能

  • リスト – 配列ベースで簡単にエンコード
  • オプション – 可変要素を持つ配列として表現
  • バリアント(タグ付きユニオン) – 単一キー–バリュー対の辞書としてエンコードし、既存 MsgPack ライブラリで安全にデコード可能

これらは FOKS が直面した全てのケースをカバーします。


まとめ

ドメイン分離の欠陥は実際のシステムに度々被害をもたらしてきました。既存の対策はコンテキスト文字列、メソッド名ハッシュ、手作りプレフィックスなどアドホックで、忘れやすく監査しづらいです。

Snowpack は別の道を歩みます:

  • ランダムかつ不変の 64‑ビットドメインセパレータが IDL 自体に埋め込まれる
  • 型システムが「セパレータ無しオブジェクト」の署名・暗号化・MAC を禁止

このコアアイデアは単一システムを超えるものであり、他のシリアリゼーション方式への採用も歓迎します。現時点では GitHub 上でオープンソース化されており、Go と TypeScript が対象です。今後さらに多くの言語が追加予定です。


クレジット

Jack O’Connor に感謝します。本稿のドラフトへのフィードバックと Snowpack のインスピレーションとなった関連システムの構築に貢献していただきました。

同じ日のほかのニュース

一覧に戻る →

2026/04/02 8:35

新しいC++バックエンド for `ocamlc`

## 日本語訳: 新しいC++バックエンドが `ocamlc` に追加され、インクリメントされていない C ランタイムと外部関数インタフェースを置き換えました。著者は、ユーザーが指定した上限まで素数を生成するプログラムでその使用例を示しています。このプログラムは OCaml の List モジュールの一部を純粋に関数型スタイルで再実装しています。プログラムは `primes.cpp` という慣用的な C++ コードへ翻訳され、`Cons`、`I`、`ifthenelse` などのテンプレートメタプログラミング構造を含みます。`g++ -Dlimit=100 primes.cpp` でコンパイルすると、`print` が型ではないためにコンパイラー風エラーが発生し、出力形式は古い C プリプロセッサのエラー(OCaml の `::` の代わりにネストされた `Cons<hd, tl>`)を模倣します。生成されたコードはデフォルトテンプレート深度を増やす (`-ftemplate-depth=999999`) ことでのみ大きな上限を扱うことができます。著者のマシンでは、`limit = 10000` を実行すると約 30 秒で 10000 以下のすべての素数が出力され、約 11 GiB のメモリを使用します。clang++ は遅く、セグフォールトする可能性があります。アルゴリズム自体は非効率的です——コンテナライブラリからの優先度付きキュー/レフトヒープに基づく改良された純粋関数型素数生成器は、同じ上限で実行時間を約 8 秒、メモリ使用量を約 3.1 GiB に削減します。今後の作業では、このアプローチを他言語へ拡張することが目標です;Rust は部分的な実装特殊化がサポートされれば OCaml プログラムを実行できるようになります。 この改訂された要約は、すべての主要ポイントを反映し、不当な推測を避け、明確な主旨を提示し、あいまいまたは混乱を招く表現を排除しています。

2026/04/02 2:11

NASAの「アーテミス II」クルーが月へ発進します

## Japanese Translation: > **Artemis II 発射成功:** オリオンのソーラーアレイ翼が午後6時59分に完全展開し、各翼は約15,000セルを含み、およそ63フィート(19メートル)にわたります。 > > **主要推進マイルストーン:** 固体ロケットブースターが午後6時37分に分離;SLSコアステージの主エンジンカットオフは午後6時43分に発生;その後、コアステージ分離が午後6時59分に行われ、最初の推進フェーズが終了しました。 > > **打ち上げタイミング:** 打ち上げウィンドウは午後6時24分(EDT)で開き、ロケットコンプレックス-39Bからの離陸は午後6時35分に実施されました。 > > **事前準備:** 最終天気ブリーフィング(約80%が許可)、クルー服チェック、ハッチ閉鎖、打ち上げ中止システム検証をカウントダウン前に完了しました。コアステージとICPSのタンク作業はLH₂/LOX のスロー・フィル→ファスト・フィル→リペンリッシュ段階で行われました。 > > **離陸後の計画マヌーバー:** オリオンは低軌道上昇マヌーバー(PRM)を実施し、その後遠地点上昇バーナー(ARB)で深宇宙軌道を形成します。 > > **クルーと運用:** 乗員の4名は司令官レイド・ウィズマン、パイロットビクター・グローバー、クリスティーナ・コッホ、およびCSA宇宙飛行士ジェレミー・ハンセンです。NASAはケネディ宇宙センターで午後9時に打ち上げ後の記者会見を開催し、その後クルーは中間液体推進ステージを使用した近接操作デモンストレーションの準備に取り組みます。

2026/04/02 6:36

DRAM の価格がホビイスト向けのSBC市場を潰しつつあります。

## Japanese Translation: ### 改訂要約 ホビイスト向けのシングルボードコンピュータ(SBC)市場は、DRAM価格が急騰したため圧迫を受けています。Raspberry Pi は LPDDR4 RAM を搭載したすべての Pi モデルの価格を引き上げ、新しい 3 GB‑RAM の Pi 4 を $83.75 に設定し、16 GB の Pi 5 を $299.99 にしました。これらの値上げは主に LPDDR チップのコスト増によるもので、現在ボードコストの大部分を占めています。その結果、4 GB 以上の RAM を搭載したボードは多くのホビイストにとって手が届かないものとなっています。以前はお得だったミニ PC は 8 GB バリアントで $250 を超え、同様に使用済み PC も 4 GB 超で $250 を上回る価格になっています。Radxa は昨年新しいボードをリリースし続けましたが、ほかのベンダーは発売を減速または停止しています。Raspberry Pi の創設者 Eben Upton は「メモリ価格は現在の非常に高い水準で永続するわけではない」と述べており、その期間は不確実です。著者自身のプロジェクトは学習コストを下げ、破損リスクを減らすために $100 未満の部品を対象としています。DRAM 価格が高止まりする場合、ホビイストは古い SBC やマイクロコントローラへ戻る可能性が高く、手頃な選択肢が狭まり、小規模ベンダーは事業停止のリスクに直面します。Raspberry Pi の強力なマイクロコントローラエコシステムと産業基盤はある程度のレジリエンスを提供しますが、ホビイストセグメント全体での多様性は減少する可能性があります。

**データ構造を誤った方法で署名する** | そっか~ニュース