ByteScope

Zstandard ファイル形式

Zstandard で圧縮されたデータ。Meta 発の高速で現代的な圧縮形式。

MIME タイプ
application/zstd
拡張子
.zst
カテゴリ
アーカイブ・圧縮

マジックナンバー(ファイル署名)

0x0000000028B52FFD(·/·Zstandard magic

Zstandard 形式について

Zstandard は gzip 並みの圧縮率をはるかに高速に達成し、レベルも細かく調整できるため、パッケージマネージャーやファイルシステムで広く採用されています。リトルエンディアンのマジックナンバーは 28 B5 2F FD です。.zst ファイルはフレームの連なりで、各フレームは 1 バイトの記述子で始まります。その記述子のビットが、後続のどのフィールドがそもそも存在するかを決めます。つまりヘッダが固定 10 バイトの gzip と違い、Zstandard のヘッダは 6 バイトから 18 バイトの間で伸縮し、5 バイト目より先に固定のオフセットは存在しません。手で読むならまずこの記述子をデコードするしかなく、近道はありません。

ヘッダーの構造(バイト単位)

オフセット長さフィールド意味
04Magic numberディスク上では 28 B5 2F FD です。仕様書はこれを 0xFD2FB528 と書きます。Zstandard の多バイト値はすべてリトルエンディアンなので、数値の表記とバイトの並びが互いに逆さまに見えるわけです。
41Frame header descriptor他のすべてが依存するバイトです。ビット 7-6 がフレームコンテンツサイズのフィールド幅、ビット 5 が single-segment フラグ、ビット 4 は未使用、ビット 3 は予約で 0 でなければならず、ビット 2 が末尾のコンテンツチェックサムを有効にし、ビット 1-0 が辞書 id の幅を与えます。コマンドラインツールからは A2 や A4 がよく出てきます。
51Window descriptor記述子のビット 5 の single-segment フラグが立っていないときだけ存在します。デコーダがバッファすべきウィンドウサイズを符号化しています。フラグが立っているとき、つまり入力全体が 1 セグメントに収まるときは、このバイトは存在せず、代わりにここからコンテンツサイズが始まります。この条件分岐を間違えるのが、zstd の解析における古典的なバグです。
variable0-4Dictionary id記述子の下位 2 ビットが選ぶ、0・1・2・4 バイトのいずれかです。0 でない値は、そのフレームが共有辞書に対して圧縮されたことを意味し、バイトがどれだけ無傷でもその辞書なしにはデコードできません。
variable0-8Frame content size展開後の長さをリトルエンディアンで、0・1・2・4・8 バイトのいずれかで表します。200000 バイトの入力は 40 0D 03 00、48 バイトの入力は 1 バイトの 30 として格納されます。エンコーダがストリーミングで長さを事前に知らなかった場合は、まるごと存在しません。
variable3Block header各ブロックの先頭に置かれる 24 ビットのリトルエンディアンのフィールドです。ビット 0 が最終ブロックであることを示し、ビット 1-2 が種別(0 が raw、1 が RLE、2 が圧縮済み、3 が予約)、ビット 3-23 がサイズです。圧縮できない入力は raw ブロックになり、00 00 10 は 131072 バイトの raw ブロック、6D 00 00 は 13 バイトの最終圧縮ブロックです。
-44Content checksum元データに対する XXH64 の下位 32 ビットで、フレームヘッダ記述子のビット 2 が立っているときだけ存在します。既定では有効なので、チェックを無効にして書かれたファイルは、単に最終ブロックの最後のバイトで終わります。

似た形式との見分け方

紛らわしい形式見分け方
skippable frames.zst は必ずしも 28 B5 2F FD で始まりません。skippable フレームはマジックナンバー 0x184D2A50 から 0x184D2A5F を使い、リトルエンディアンで 50 2A 4D 18 から 5F 2A 4D 18 として格納され、そのあとに 4 バイトのリトルエンディアンのサイズが続きます。デコーダはこれを飛び越え、アプリケーションは独自メタデータの埋め込みに使います。したがってオフセット 0 に圧縮フレームのマジックを要求する検出器は、まったく正しいファイルを拒否します。
XZ同じ仕事を巡る直接のライバルで、どちらを使うべきかという検索の大半はこの比較です。FD 37 7A 58 5A 00 と 28 B5 2F FD。最大設定での圧縮率は今も xz が勝ちますが、Zstandard は両端の速度で圧倒的に勝ち、レベル 19 でも十分渡り合います。
GZIP1F 8B と 28 B5 2F FD。Zstandard は gzip の圧縮率を数倍の速度で出すことを明確な狙いとして設計されたので、同じニッチを占めていて、そのまま差し替えられます。ビルドスクリプトの中で .zst が .gz という名前になってしまうのは、まさにそういう経緯です。
ZIPZIP の圧縮方式 93 は Zstandard なので、マジックがオフセット 0 ではなく ZIP エントリの中に現れることがあります。一部の書き手以外での対応は薄いため、そういうアーカイブは、他のあらゆる ZIP を問題なく読めるツールでもしばしば開けません。
TAR.tar.zst はパッケージのペイロードとしてごく普通の形です。フレームの中には、単一ファイルを圧縮したものと区別できるものが何もありません。展開して、出力のオフセット 257 が ustar かどうかを確認してください。

よくある壊れ方

  • 長さが宣言されたままの途中切れ。フレームコンテンツサイズがヘッダにあった場合、ツールは想定される出力サイズをまるごと報告してから、途中でフレームの想定外の終端として失敗します。数値はデータが途切れる瞬間まで正しく見えます。
  • チェックサムを無効にして書かれたフレーム。末尾の 4 バイトが単に無いので、出力を検証するものがありません。raw ブロックの内側の破損は、エラーも出さずに誤ったバイトを生みます。raw ブロックはそのままコピーされるだけで、脱線するエントロピー符号が存在しないからです。
  • 辞書の欠落。辞書 id フィールドが 0 でないフレームは、ディスク上のバイトがすべて無傷でも、その辞書そのものが無ければデコードできません。破損エラーではなく辞書の不一致として失敗するので、存在しない損傷を探しに行く羽目になります。
  • 連結されたフレームを 1 つとして読んでしまうケース。.zst の連結は合法で、標準ツールは全フレームを順に展開します。最初のフレームの最終ブロックで止めるリーダーは、黙って結果を切り詰めます。間に skippable フレームが挟まっていると事態はさらに悪化します。
  • テキストモード転送。ヘッダは生き残り、宣言されたコンテンツサイズも正しく読め、最初の圧縮ブロックの中でデコードが失敗します。つまり実際に使う瞬間まで、ファイルは正しい Zstandard として認識され続けます。

この形式の現在地

Zstandard はここ数年で汎用圧縮の既定の座に就き、今も広がり続けています。Arch と Fedora のパッケージ、Debian のパッケージペイロード、btrfs と ZFS の透過圧縮、コンテナイメージのレイヤー、Kafka と RocksDB の内部、そして Linux が自前の initramfs イメージに使う圧縮まで、すべてこの上に乗っています。しかも単一プロジェクトの形式ではなく、RFC 8878 として公開されたインターネット標準です。理由はどれか 1 つの数字ではなく、トレードオフ曲線の形にあります。既定レベルで gzip の圧縮率をおおむね維持しながら圧縮は数倍速く、展開は速いうえにレベルにほとんど左右されません。つまり高いレベルを選んでも、代償を払うのは書き手だけで、読み手は一切払いません。他のよくある形式にはない辞書対応もあり、これが似たような小さいペイロードを大量に圧縮する場面を一変させます。今も負けているのは、保管用の最大圧縮率で xz と LZMA が先を行っている点と、長い尾を持つ互換性で gzip が無敵である点です。

Zstandard ファイルをこのサイトで開く

どれもブラウザ内で動きます。ファイルが端末から出ることはありません。

関連する形式

Zstandard と混同しやすい形式です。先頭バイトを見比べてください。

形式先頭バイト拡張子
GZIP1F 8B.gz
XZFD 37 7A 58 5A 00.xz
BZIP242 5A 68.bz2
ZIP50 4B 03 04.zip

よくある質問

ファイルのマジックナンバーとは何ですか?

ファイル先頭の数バイトで、名前が何であろうとその形式を示すものです。PNG は必ず 89 50 4E 47 で始まり、ZIP は 50 4B 03 04 で始まります。OS もブラウザも file コマンドも、拡張子を信用せずこのバイト列を読みます。だからファイル名を変えても中身の正体は変わりません。

マジックナンバーを自分で確認する方法は?

macOS や Linux なら xxd -l 16 ファイル名 で先頭 16 バイトが表示されます。Windows なら PowerShell で Format-Hex -Path ファイル名 -Count 16 です。あるいはこのサイトのファイル形式判別ツールにドロップすれば、ローカルでバイト列を読んで形式を教えてくれます。アップロードはありません。

2 つの形式が同じマジックナンバーを持つのはなぜ?

一方が他方の上に作られているからです。docx、xlsx、pptx、apk、jar、epub はすべて中身が ZIP アーカイブなので ZIP の署名で始まり、区別するには内部のエントリを見る必要があります。Java の class ファイルと macOS のユニバーサルバイナリはどちらも CA FE BA BE で始まり、直後のフィールドで見分けます。

マジックナンバーがまったくないファイルもある?

あります。XML、HTML、JSON、SVG、CSV といったテキストベースの形式には固定のバイト署名がないため、構造から判別します。先頭の <?xml 宣言、<svg 要素、あるいは { に続く引用符付きのキーなどです。これは確定ではなく推測なので、このリファレンスではそうした形式をプローブ判別として示しています。

マジックナンバーが一致すればそのファイルは安全?

いいえ。わかるのは形式であって、中身が無害かどうかではありません。正規の PDF や docx でも悪意のあるペイロードを含んでいることがあります。特に拡張子とバイト列が食い違うときに真の形式を知るのは有用な第一段階ですが、マルウェアスキャンではありません。

Zstandard かもしれないファイルをお持ちですか?ファイル形式判別ツールで調べる — マジックナンバーをローカルで読み取ります。アップロードは一切ありません。またはすべての形式を見る。