この記事は、インテル® ソフトウェア・ネットワークに掲載されている「Intel(R) Digital Random Number Generator (DRNG) Software Implementation Guide」(http://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide/) の日本語参考訳です。
1 はじめに
インテル® セキュアキー (開発コード名: Bull Mountain) は、インテル® 64 アーキテクチャーおよび IA-32 アーキテクチャーの RDRAND 命令と DRNG (Digital Random Number Generator、デジタル乱数ジェネレーター) ハードウェア実装に対してインテルが付けた名称です。RDRAND 命令を使用した DRNG は、暗号プロトコル用の高い品質の鍵生成に役立ちます。
このガイドでは、RDRAND の使用法に関するさまざまな技術情報を説明します (コードサンプル付き)。 以下のセクションが含まれます。
セクション 2: 乱数ジェネレーター (RNG) の基本と DRNG の紹介: RNG の性質と擬似乱数ジェネレーター (PRNG) および真性乱数ジェネレーター (TRNG) の実装のバリエーションについて説明します (最近のカスケード構造 RNG を含む)。次に、この広範な分類における DRNG の位置を示します。
セクション 3: DRNG の概要: コンポーネント・アーキテクチャー、ロバストネス機能、アクセス方法、パフォーマンス、電力要件など、DRNG の技術的な概要を説明します。
セクション 4: RDRAND 命令の使用法: RDRAND 命令のリファレンス情報とコードサンプルを紹介します。RDRAND プラットフォーム・サポートの検証と DRNG ベースのライブラリーにおける推奨事項も含まれます。
このドキュメントは、多くの読者の役に立つことを目的としています。RNG の性質をすでに理解している開発者は、セクション 4 に進み、RDRAND 命令のリファレンスとコードサンプルを参照してください。RNG の基本から知りたい方は、次のセクション 2 に進み、DRNG の性質と重要性を示す概念からお読みください。DRNG の技術的な概要を知りたい方は、セクション 3 をご覧ください。
2 RNG の基本と DRNG の紹介
RDRAND 命令を使用したデジタル乱数ジェネレーターは、高性能なエントロピーと乱数を生成する革新的なハードウェア・アプローチです。このセクションでは、既存の RNG ソリューションとの違いを理解するため、乱数生成の基本的な概念について説明します。
2.1 乱数ジェネレーター (RNG)
乱数ジェネレーター (RNG) とは、値が予測できない [最小, 最大] の間の数のシーケンスを生成するユーティリティーまたはデバイスです。技術的には、次の特徴が求められます。
- 新しい値はそれぞれ、前の値と統計的に独立していなければなりません。つまり、生成される値のシーケンスで特定の値が、RNG のランダムシーケンスの次の値として続いてはなりません。
- インターバルから選択される数の全体的な分布は一様分布であるため、RNG の出力ですべての数は等しく、ほかの数よりも「ポピュラーな」 (頻繁に出現する) 数はありません。
- シーケンスが予測できないため、攻撃者は生成されるシーケンスの一部またはすべての値を推測することができません。予測は、前方予測 (将来の値) と後方追跡 (過去の値) によって行われます。
コンピューティング・システムは本来決定論的 (デターミニスティック) であるため、これらの特性 (統計的に独立し、一様分布で、予測できない) を持つ品質の乱数を生成することは、一般に思われているよりもはるかに困難です。システムクロックから秒の値をサンプリングする一般的なアプローチは十分ランダムに思えますが、プロセス・スケジューリングとその他のシステムの影響により、一部の値がほかの値よりも頻繁に出現することはよくあります。ユーザーのキーストロークやマウス移動の時間のような外部エントロピー・ソースを用いた場合も同様に、詳しく解析すると、すべての値が平等に分布することはまずありません。一部の値はほかの値よりも多く出現し、特定の値はほとんど出現しません。
これらの要件以外に望ましい RNG の特性として、以下のものがあります。
- RNG は、高速に値を返し (応答時間が短い)、短時間に大量のリクエストを処理できる (高度にスケーラブルである)。
- RNG は、出力を予測したり、出力や操作に影響を与えるために根本的な状態を観察または変更する攻撃者に対して安全である。
2.2 擬似乱数ジェネレーター (PRNG)
優れた RNG の統計的動作を達成するために広く用いられている 1 つのアプローチは、擬似乱数ジェネレーター (PRNG) の生成における数学的モデリングの活用です。PRNG は決定論的アルゴリズムで、ランダムに「見える」数のシーケンスを計算するソフトウェアに実装されます。PRNG には、モデルの状態を初期化するシード値が必要です。シードを使用して初期化を行うことで、優れた統計的動作を表す数のシーケンスを生成することができます。
PRNG には、内部状態モデルのサイズに依存した周期性があります。つまり、長い数のシーケンスを生成して、内部状態のすべてのバリエーションが使用されると、以前のシーケンスと同じ数のシーケンスが繰り返されます。ただし、現在利用可能な最高の PRNG アルゴリズムでは、非常に長い周期が利用されているため、この弱点は実際には気にする必要はありません。例えば、32 ビット・ワード長の Mersenne Twister MT19937 PRNG の周期は 219937-1 です。[1]
すべての PRNG の重要な特徴は、PRNG は決定論的であることです。そのため、同じシードが指定されると、同じ PRNG は完全に同じ「ランダムな」数のシーケンスを常に生成します。これは、PRNG は特定の内部状態と十分に定義されたアルゴリズムに基づいて次の値を計算しているためです。その結果、生成される値のシーケンスがランダムな統計的特性 (独立、一様分布) を示していたとしても、PRNG のすべての動作を完全に予測することができます。
状況によっては、PRNG の決定論的性質は利点になります。例えば、シミュレーションや実験で、研究者が同じ入力データのシーケンスを使用して異なるアプローチの結果を比較したい場合、同じシード値の、同じ PRNG を使用して、繰り返し可能な、長いランダムデータ入力のシーケンスを生成することができます。
ただし、ほかの状況では、この決定論的性質は大きな欠点になります。セキュアな通信チャネル上におけるクライアント・アプリケーションとのデータ交換の暗号化鍵として使用する乱数を生成するサーバー・アプリケーションについて考えてみましょう。使用される PRNG とシード値 (またはシード値を取得するためのアルゴリズム) を知っている攻撃者は、生成されるすべての鍵 (乱数) をすばやく予測することができます。知られていない洗練されたシード処理アルゴリズムを使用した場合でも、使用される PRNG を知っている (または推測できる) 攻撃者は、出力値のシーケンスを観察することで PRNG の状態を特定することができます。非常に少ない観察 (例えば、Mersenne Twister MT19937 では 624 回) だけで、後続する値をすべて予測することが可能です。このような理由により、PRNG は暗号論的に安全でないと考えられています。
PRNG 研究者は、CSPRNG (Cryptographically Secure PRNG、暗号論的擬似乱数ジェネレーター) を作成することで、この問題を解決しようとしました。このために、連続する整数のシーケンスに暗号ハッシュを適用する手法、連続する整数のシーケンスにブロック暗号を使用する手法 (カウンターモード)、XORing a stream of PRNG が生成する数のストリームと平文の XOR (排他的論理和) を計算する手法 (ストリーム暗号) などのさまざまな手法が開発されました。
これらのアプローチでは、計算の複雑さが大幅に増すことにより PRNG とその状態が推測される可能性は低くなりますが、最終的な値は強健な乱数ジェネレーターに求められる正しい統計的特性 (独立性、一様分布) を示すこともあれば、示さないこともあります。さらに、決定論的アルゴリズムはすべて、さまざまな手段 (例えば、逆アセンブラーを使用した解析、高度なメモリー攻撃、従業員からの漏洩) により攻撃者に発見される可能性があります。一般に、攻撃者は、可能な値の範囲を絞ったり、何らかの方法でメモリーを調べることにより、PRNG のシードを発見したり推測します。一度でも決定論的アルゴリズムとシードが知られてしまうと、攻撃者は、過去および将来も含めて、生成されるすべての乱数を予測できるようになります。
2.3 真性乱数ジェネレーター (TRNG)
PRNG の決定論的性質が問題となる状況 (例えば、ゲームやコンピューター・セキュリティー) では、より優れたアプローチとして真性乱数ジェネレーター (TRNG) が利用されます。
数学的なモデルを使用してランダムに見える正しい統計的特性を持つ数を決定論的に生成する PRNG とは異なり、TRNG は、あるタイプの物理的なソースからランダム性 (エントロピー) を抽出し、そのランダム性を利用して乱数を生成します。物理的なソースはエントロピー・ソースとも呼ばれ、TRNG を使用するコンピューティング・システムでそのまま利用可能な、または利用可能になる、さまざまな物理的現象から選択することができます。例えば、ユーザーのキーストロークやマウス移動の時間をエントロピー・ソースとして使用することができます。以前指摘したように、この手法は実際には自然のままであり、生成されるシーケンスは一般に正しい統計的特性を満たしていません。TRNG でエントロピー・ソースとして何を使用すべきかという点は、TRNG 設計者が直面する重要な問題です。
統計的な正しさ以外に、高速でスケーラブルである (つまり、短時間に大量の乱数を生成できる) ことも TRNG に望まれる点です。コンピューティング・システム外部のエントロピー・ソースのサンプリングには通常、近年のコンピューター・システムの処理速度に影響する、デバイス I/O と長い遅延時間が必要になるため、多くの TRNG で深刻な問題となります。一般に、TRNG におけるエントロピー・ソースのサンプリングは、PRNG で必要な計算 (単に次の乱数を計算) よりも遅くなります。この理由により、PRNG は TRNG よりもはるかにパフォーマンスが高く、よりスケーラブルです。
しかし、PRNG とは異なり、TRNG は決定論的ではありません。つまり、TRNG ではシードを処理する必要はなく、シーケンスの乱数の選択を予測することは非常に困難です。そのため、攻撃者は、効果的な方法で特定の乱数シーケンスを観察して後続する値を予測することができません。この特性は、TRNG に周期性がないことも意味します。ランダムなシーケンスの繰り返しは起こりえます (実際にはまずありません) が、その繰り返しを攻撃者にとって便利な方法で予測することはできません。
2.4 カスケード構造 RNG
近年のオペレーティング・システム (Linux* など) と暗号化ライブラリーで使用される一般的なアプローチは、エントロピーのバッファーまたはプールを供給するためにエントロピー・ソースから入力を取得します。このエントロピー・プールは、暗号論的擬似乱数ジェネレーター (CSPRNG) の周期的なシードとなる非決定論的乱数を提供するために使用されます。CSPRNG は、真ランダムに見えて、よく定義されたレベルの計算攻撃に耐える、暗号論的に安全な乱数を生成します。
この手法の重要な利点はパフォーマンスです。エントロピー・ソースのサンプリングは通常、デバイス I/O を使用し、リアルタイム・サンプリング・イベントの発生を待つために遅いと前述しました。対照的に、CSPRNG の計算はプロセッサー・ベースであり、I/O とエントロピー・ソースの遅延が回避されるため高速です。低速なエントロピー・ソースによる周期的なシードの取得と、1 つのシードから大量の乱数を生成できる高速な CSPRNG を組み合わせることで、このアプローチは TRNG よりも優れたパフォーマンスを実現します。
図 1: カスケード構造乱数ジェネレーター
このアプローチは理想的に見えますが、実際にはそれとはかけ離れています。まず、実装がソフトウェアで行われるため、広範なソフトウェア攻撃に対して脆弱です。例えば、重要な状態の要求が、メモリーベースの攻撃やタイミング攻撃につながる可能性があります。次に、このアプローチでは、どのエントロピー・ソースを使用すべきかという問題が解決されません。外部ソースがなければ、エントロピーの品質は低くなります。例えば、システムが大規模なデータセンター内にある場合、ユーザーイベント (マウス、キーボードなど) のサンプリングは不可能です。外部のエントロピー・ソースを使用できても、エントロピーのサンプリングは遅いため、シードイベントの機会は少なくなります。
2.5 デジタル乱数ジェネレーター (DRNG)
デジタル乱数ジェネレーター (DRNG) は、高品質で高性能なエントロピーと乱数を生成する革新的なハードウェア・アプローチです。DRNG は、インテル® 64 アーキテクチャーの新しい RDRAND 命令と DRNG ハードウェア実装から構成されます。
前述の RNG 分類でいえば、DRNG はカスケード構造 RNG モデルに続くモデルで、プロセッサー常駐のエントロピー・ソースを使用してハードウェアで実装された CSPRNG のシードを繰り返し行います。ソフトウェア・アプローチと異なり、DRNG には、高品質のエントロピーで CSPRNG のシードを繰り返しすばやくサンプリングできる、高品質のエントロピー・ソース実装が含まれます。DRNG は、内部状態に対するソフトウェア攻撃から隔離された、自給自足のハードウェア・モジュールです。その結果、統計的特性 (独立、一様分布)、予測が非常に困難な乱数シーケンス、ハイパフォーマンス、攻撃からの保護という、相当な強健さを備える RNG ソリューションとなります。
このデジタル乱数生成の手法は、プロセッサー・チップのハードウェアに実装された機能を利用して真性乱数を生成する独特なアプローチで、インテル® 64 命令セットに追加された新しい命令から利用することができます。そのため、応答時間はソフトウェアで実装されたほかの PRNG アプローチに匹敵します。このアプローチは、DRNG をソフトウェア・ベースの PRNG の単なる高品質なシードではなく、乱数の排他的なソースとして使用する、さらに要求の厳しいアプリケーションでも十分スケーラブルです。すべての権限レベルで実行でき、中間のソフトウェア・スタック、ライブラリー、オペレーティング・システムの制御を介することなく、命令セットで乱数を取得することができます。
RDRAND を使用すると、NIST SP800-90、FIPS-140-2、ANSI X9.82 などのさまざまな暗号化規格の実装による強健さが保証され、操作の手法の透明性が提供されます。これらの規格に準拠することにより、RDRAND を使用したデジタル乱数生成は、政府機関や商用向けの高度に規制されたアプリケーションで実現可能なソリューションとなるでしょう。
デジタル乱数生成については、セクション 3 で詳細に説明します。DRNG を使用したインテル® 64 命令セット拡張である RDRAND の使用については、セクション 4 で説明します。
2.6 デジタル乱数ジェネレーター向けアプリケーション
情報セキュリティーは DRNG を利用する重要なアプリケーションです。暗号プロトコルは、リプレイ攻撃を防ぐための鍵と、新しい (一時的な) セッション値の生成を RNG に依存しています。事実、暗号プロトコルには相当な強健さが備わっていますが、根本的な鍵生成手法が弱い場合は、広範な攻撃に苦しめられることになります (例えば、Debian/OpenSSL の大失敗 [3])。DRNG を使用すると、この脆弱性を解消できるため、暗号の強度を大幅に高めることができます。
これに密接に関連するのは、政府機関や工業向けアプリケーションです。情報の機密性により、これらのアプリケーションは、FISMA、HIPPA、PCIAA のようなセキュリティー規格に準拠している必要があります。RDRAND は、NIST SP800-90、FIPS 140-2、ANSI X9.82 のような既存のセキュリティー規格を満たすように設計されており、さまざまな情報セキュリティー規格に準拠した RNG ソリューションを提供します。
DRNG のその他の用途として以下のようなものがあります。
- 通信プロトコル
- モンテカルロ・シミュレーションや科学計算
- ゲーム・アプリケーション
- 安全なディスクワイプやドキュメント・シュレッドのようなエントロピー・アプリケーション
- RNG 攻撃に対するオンラインサービスの保護
3 DRNG の概要
このセクションでは、RDRAND 命令を使用した DRNG のコンポーネントと、コンポーネント間のインタラクション (対話) について説明します。
3.1 プロセッサー・チップ
図 2 は、RDRAND 乱数生成の様子を示しています。この図で、DRNG はプロセッサー・チップのハードウェア・モジュールとして表されています。各コアはインターコネクト・バスにより接続されています。
図 2: RDRAND 設計を使用したデジタル乱数ジェネレーター
RDRAND 命令 (セクション 4 で詳しく説明) は、各コアのマイクロコードによって制御されます。プロセッサー・チップの DRNG ハードウェア・モジュールとのインタラクションを制御する RNG マイクロコード・モジュールもこの中に含まれます。
3.2 コンポーネント・アーキテクチャー
図 3 で示されているように、DRNG は、非同期のプロダクション・パイプラインを形成する、約 3Gbps の非決定論的ハードウェア・プロセスからランダムなビットを生成するエントロピー・ソース (ES)、ES が生成したエントロピーを AES[4] を CBC-MAC[6] モードで使用して高品質な非決定論的乱数に改善するコンディショナー、コンディショナーの出力をシードとする決定論的ランダム・ビット・ジェネレーター (DRBG) の 3 つの論理コンポーネントと見なすことができます。
コンディショナーは、前述のカスケード構造 RNG におけるエントロピー・プールと同等と考えることができます。ただし、コンディショナーは、下流工程が消費できるよりも高速な、エントロピーの高品質、高速、連続的なストリームにより供給されるため、エントロピー・プールを維持する必要はありません。代わりに、過去および将来のエントロピーと無関係な新しいエントロピーの条件付けを常に行います。
最後のステージは、CTR モードにおける AES に基づき、SP800-90 に準拠したハードウェア CSPRNG です。SP800-90 では、DRBG (Deterministic Random Bit Generator、決定論的ランダム・ビット・ジェネレーター) と呼ばれます。このドキュメントでは、この用語を使用しています。
図 3: DRNG コンポーネント・アーキテクチャー
3.2.1 エントロピー・ソース (ES)
非決定論的ランダム・ビット・ジェネレーター (NRBG) として知られる、オールデジタルのエントロピー・ソース (ES) は、0 と 1 の形式で、エントロピー・データのシリアルなストリームを提供します。
ES は、セルフタイム回路で非同期に実行され、シリコン内の熱雑音を使用してビット (レート 3GHz) のランダムなストリームを出力します。また、ほかのコアロジックと同じ電源を使用して実行されるため、専用の外部電源は必要ありません。ES は、プロセッサーの通常の動作範囲を超えた、広範な動作条件で適切に機能するように設計されています。
ES から出力されたビットは、品質改善のためにコンディショナーに渡されます。
3.2.2 コンディショナー
コンディショナーは、ES により生成された 256 ビットの未加工のエントロピー・サンプルのペアを受け取り、AES-CBC-MAC を使用して品質改善された 256 ビットの 1 つのエントロピー・サンプルを出力します。コンディショナーで処理することで、エントロピー・サンプルは、偏りが少ない、より高品質なサンプルに改善されます。
AES (Advanced Encryption Standard、新暗号化規格) の定義は、FIPS-197 Advanced Encryption Standard [4] を参照してください。CBC-MAC (Cipher Block Chaining – Message Authentication Code、暗号ブロック連鎖 – メッセージ認証コード) の定義は、NIST SP 800-38A Recommendation for Block Cipher Modes of Operation [6] を参照してください。
品質改善されたエントロピーは 1 つの 256 ビット値として出力され、パイプラインの次の段階である DRBG に渡されて、シード値として使用されます。
3.2.3 決定論的乱数ビット・ジェネレーター (DRBG)
決定論的乱数ビット・ジェネレーター (DRBG) の役割は、品質改善されたエントロピー・サンプルを大きなセットの乱数に「広げて」、ハードウェア・モジュールで利用可能な乱数の量を増やすことです。この処理は、規格に準拠した DRBG を使用し、品質改善されたエントロピー・サンプルを継続的に新しいシードにすることにより行われます。
この機能のために選択された DRBG は、NIST SP 800-90 [5] のセクション 10.2.1 で定義されている、AES ブロック暗号を使用する CTR_DRBG です。生成された値は FIFO 出力バッファーに格納され、乱数の RDRAND 要求に応答するために使用されます。
DRBG は、シードをいつ変更してバッファーの乱数プールを新しくするか自主的に決定します。RDRAND の呼び出し元は、シードが変更されたことは分かりますが、シードがいつ変更されるか予測することはできません。シードごとに、511 個を上限とする 128 ビットのサンプルが生成されます。つまり、同じシード値から 511*2=1022 個以上の連続する DRNG 乱数が生成されることはありません。
3.3 強度と自己検証
DRNG の機能に高度な信頼性と強健さがあることを保証するため、実行中とシステムのスタートアップ時に動作する検証機能が用意されています。検証機能には、DRNG OHT (Online Health Test) と BIST (Built-In Self Test) があります。どちらも図 4 で示されています。
図 4: DRNG 自己検証コンポーネント
3.3.1 OHT (Online Health Test)
OHT (Online Health Test、オンライン・ヘルス・テスト) は、ハードウェアのサンプルごとのテストとスライディング・ウィンドウ統計テストの両方を使用して、ES で生成されたエントロピーの質を測定します。
サンプルごとのテストは、ES の数学的なモデルにより指定されたと予想されるパターンの到着分布とビットパターンを比較します。このテストをパスしない ES サンプルは「unhealthy (異常)」とマークされます。この区別を使用して、コンディショナーは、少なくとも 2 つの正常なサンプルが各シードに混合されることを保証し、ES 出力のエントロピーの内容を変更するハードウェア攻撃を防ぎます。
スライディング・ウィンドウ・テストは、サンプルがしきい値を超えていないか、サンプルの状態を確認します。スライディング・ウィンドウのサイズは大きく (65536 ビット)、全体的なメカニズムで、ES が乱数を発行する前に正しく動作していたことを保証します。DRNG がランタイム中に失敗すると (まれに起こります)、品質の低い乱数を発行するのではなく、乱数の発行を中止します。
3.3.2 BIST (Built-In Self Test)
BIST (Built-In Self Test、ビルトイン自己テスト) は、DRNG をソフトウェアで利用する前に、ES が正常であることを確認するテストです。BIST には、本来統計的なエントロピー・ソース・テスト (ES-BIST) および BIST 既知解テスト (KAT-BIST) による DRNG の決定論的下流ロジックすべてを対象とする包括的なテストが含まれます。
ES-BIST では、DRNG をソフトウェアで利用する前に、ノーマルモードで一定期間 DRNG を実行します。このテストにより、OHT は、ES 操作が正常であると結論を出す前に、フル・スライディング・ウィンドウ (256 サンプル) の ES サンプルが正常かどうかを調べることができます。さらに、後続の ES サンプルが正常であることを保証するためにスライディング・ウィンドウにサンプルを格納し、PRNG にシードを提供して、乱数を DRNG の出力キューに格納します。
KAT-BIST は、決定論的入出力検証を使用して、OHT とエンドツーエンドの正当性の両方をテストします。まず、統計的品質が低い数を含む、さまざまなビット・ストリーム・サンプルが OHT に入力されます。サンプルは広範な統計的特性をカバーし、ロジックが「異常な」サンプルを正しく識別するかどうかテストします。KAT-BIST フェーズで、決定論的乱数がパイプラインの最後から連続して出力されます。BIST 出力テストロジックは、予想した出力を受け取ったことを確認します。
スタートアップ中に失敗した BIST があった場合、DRNG は乱数の発行を拒否し、失敗した BIST があったことをオンチップテスト回路に通知します。この BIST ロジックにより、DRNG のセキュリティーを損なう可能性がある、従来のオンチップテスト手法 (例えば、スキャンや JTAG) を使用する必要がありません。
3.4 RDRAND
DRNG へのソフトウェア・アクセスは、新しい RDRAND 命令を使用して行います。
RDRAND は、DRNG からハードウェアで生成された乱数を取得して、命令の引数として指定されたデスティネーション・レジスターに格納します。乱数のサイズ (16 ビット、32 ビット、または 64 ビット) は、指定されたレジスターのサイズによって決定されます。キャリーフラグ (CF) を調べて乱数が命令実行時に利用可能だったかどうか確認する必要があります。
RDRAND は、プラットフォーム上で動作する任意のシステムまたはアプリケーションで利用できることに注意してください。つまり、プロセスの権限レベルに基づいてアクセスを制限するハードウェア要件はありません。そのため、RDRAND は、オペレーティング・システムやハイパーバイザー・システム・ライブラリー、共有ソフトウェア・ライブラリーの一部として、あるいはアプリケーションから直接実行することができます。
使用するインテル® プラットフォームが RDRAND をサポートしているかどうかプログラムで確認するには、CPUID 命令を使って ECX レジスターのビット 30 を調べます。詳細は、参考文献 [7] を参照してください。
3.5 パフォーマンス
複数のコア/スレッドで共有されるハイパフォーマンスなエントロピー・リソースになることを目指して、RDRAND と組み合わされた DRNG は、新しい世代の RNG パフォーマンスを提供します。
DRNG は、プロセッサー・チップの一部としてハードウェアに実装されます。そのため、エントロピー・ソースと DRBG はどちらもプロセッサーのクロック速度で実行されます。ほかのハードウェア・ベースのソリューションと異なり、エントロピー・サンプルを取得するのにシステム I/O が必要ありません。また、複数のリクエストが出された際にエントロピーの転送が遅くなったり、ボトルネックの原因となるオフチップバスのレイテンシーもありません。
乱数は命令レベルのリクエスト (RDRAND) により直接伝えられます。そのため、オペレーティング・システムとソフトウェア・ライブラリーのいずれもリクエストを制御する必要がありません。DRNG は、ワークロードの多いサーバー・アプリケーションでも十分スケーラブルです。DRNG のステートレスな設計とアトミックな命令アクセスにより、仮想化のコンテキスト内では、ハイパーバイザーの介入やリソース管理なしで、複数の VM から RDRAND を自由に使用することができます。
下記のグラフは、第 3 世代インテル® Core™ プロセッサー (開発コード名: Ivy Bridge) を搭載したシステム上でプリプロダクション・サンプルから取得した実験データを示しています。
ハードウェア: 第 3 世代インテル® Core™ プロセッサー (開発コード名: Ivy Bridge)、クアッドコア、4GB メモリー、ハイパースレッディング有効。
ソフトウェア: Linux* Fedora 14、RDRAND 対応 GCC バージョン 4.6.0 (experimental)、スレッドカーネル API を使用。
スループットの測定結果:
- 最大 7000 万回の RDRAND を実行 (毎秒)
- 500MB を超えるランダムなデータを処理 (毎秒)
- スループットの上限は並列スレッドの数とは無関係
定常状態はピーク・パフォーマンスで維持されている点に注意してください。
RDRAND の応答時間とシード変更の頻度
- 実行ごとに ~150 クロック
注: 共有データパスが DRNG からコアまでに制約されるため、CPU のクロック周波数によって異なります。 - 8 スレッドまで多少の競合がある
– 2 コアチップの場合は 4 スレッドまで
- スレッドが追加されるとともに単純に増加
– DRNG のシード変更の頻度
- 単一スレッドの最長のケース: 4 回 RDRAND を実行するたびにシード変更
- 複数スレッドの最長のケース: 23 回 RDRAND を実行するたびにシードを変更
- 実行回数が少ない場合は、2 回 RDRAND を実行するたびにシードを変更
– NIST SP 800-90 推奨 ≤ 248
3.6 電力要件
DRNG ハードウェアは、プロセッサー・チップ上に存在します。実行するために専用の電源は必要ありません。代わりに、プロセッサーのローカルの電源を使用します。セクション 3.2.1 で述べたように、DRNG は、プロセッサーの通常の動作範囲を超えた、広範なプロセス、電圧、温度 (PVT) レベルで機能するように設計されています。
DRNG は、個々のコアに関連した電力管理メカニズムやアルゴリズムに影響しません。例えば、コア単位でプロセッサーのパフォーマンス状態 (P-ステート) とプロセッサーのアイドル状態 (C-ステート) を調整する ACPI ベースのメカニズムに影響しません。
電力を節約するため、キューがフルの際、DRNG はクロックゲートを行い、自身をオフにします。このアイドルベースのメカニズムにより、エントロピー計算やポスト処理が必要ないときは常に、消費電力をわずかに抑えます。
4 RDRAND 命令の使用法
このセクションでは、開発者向けに RDRAND 命令のリファレンス情報とコードサンプルを紹介します。このガイドのすべてのコードサンプルは、新しい三条項 BSD ライセンスの下に公開されており、ほぼすべてのソフトウェア・コンテキスト内で自由に利用できます。
RDRAND の使用法とコードサンプルの詳細は、参考文献 [7] を参照してください。
RDRAND のサポートの確認
RDRAND 命令を使用する前に、アプリケーションやライブラリーでは、プラットフォームがこの命令をサポートしているかどうか (プラットフォームに DRNG 機能が含まれているかどうか) を最初に確認する必要があります。この確認は、CPUID 命令を使用して行うことができます。一般に、CPUID は、EAX、EBX、ECX、および EDX レジスターに格納されているプロセッサー ID と機能情報を取得するために使用されます。CPUID の詳細は、参考文献 [8] および [9] を参照してください。
具体的には、CPUID 命令を使用して ECX レジスターのビット 30 を調べることで RDRAND のサポートを確認できます。表 1 (下記) および参考文献 [7] の 2-23 で示されているように、値が 1 の場合はプロセッサーが RDRAND 命令をサポートしていることを、値が 0 の場合はプロセッサーが RDRAND 命令をサポートしていないことを示します。
ビット番号 | ニーモニック | 説明 |
---|---|---|
30 |
RDRAND |
値が 1 の場合、プロセッサーが RDRAND 命令をサポートしていることを示します。 |
表 1: ECX レジスターに返される機能の情報
C/C++ のような高水準言語のコンテキスト内で CPUID 命令を呼び出す手法は 2 つあります。
- インライン・アセンブリー・ルーチン
- 個々のファイルで定義されたアセンブリー・ルーチン
ここで示す多くのサンプルでは、両方の手法を説明します。インライン・アセンブリーの利点は、ソースコードのコンテキスト内で容易に判読可能なことです。ただし、欠点は、異なるプラットフォームを制御するには条件付きコードが必要になることです。条件付きコードを追加すると、コードの判読が難しくなります。このため、個別のファイルにアセンブリー・ルーチンを定義して、宣言した名前でルーチンを呼び出す方法がよく使用されます。この方法を使用することで、オリジナルのソースコード (ルーチンの呼び出し元) を変更することなく、ビルドシステムで異なるプラットフォーム・ターゲット向けに同じルーチンの複数のコードバージョンから選択するように制御できます。
この実装ガイドでは Linux* の実装について説明しています。Windows* および Mac* OS のサンプルについては、DRNG のダウンロードを参照してください。
– 注: メモリーには何も格納されません。これらのサンプルはある理由のために特定の方法で記述されています。
サンプル 1 は、64 ビット Linux* 上での gcc コンパイル用に関数 get_cpuid_info_v1
を定義しています。
.intel_syntax noprefix .text .global get_cpuid_info_v1 get_cpuid_info_v1: mov r8, rdi # array addr mov r9, rsi # leaf mov r10, rdx # subleaf push rax push rbx push rcx push rdx mov eax, r9d mov ecx, r10d cpuid mov DWORD PTR [r8], eax mov DWORD PTR [r8+4], ebx mov DWORD PTR [r8+8], ecx mov DWORD PTR [r8+12], edx pop rdx pop rcx pop rbx pop rax ret 0 #get_cpuid_info_v1 ENDP #_TEXT ENDS
コードサンプル 1: CPUID を使用して 64 ビット Linux* における RDRAND のサポートを検出します。
ファイル get_cpuid_v1_lix64.s で定義されたルーチンは、次のように gcc でコンパイルしてオブジェクト・コードにすることができます。
gcc -g -c get_cpuid_v1_lix64.s -o get_cpuid_v1_lix64.o
インテル® 64 アセンブリー・ルーチンを使用するには、まず最初に、ルーチンに渡されるデータ構造を get_cpuid_v1_lix64.h のようなヘッダーファイルに定義します。
typedef struct { unsigned int EAX; unsigned int EBX; unsigned int ECX; unsigned int EDX; } CPUIDinfo; extern void get_cpuid_info_v1(CPUIDinfo *info, const unsigned int func, const unsigned int subfunc);
コードサンプル 2: アセンブリー・ルーチンの呼び出し元によって使用されるヘッダーファイル
このヘッダーファイルは、関数を宣言し、extern
を使用して外部で定義されることを示します。
このアセンブリー・ルーチンを C/C++ プログラムから呼び出すには、上記のヘッダーファイルをインクルードし、結果を保持する CPUIDinfo
オブジェクトを作成して、外部で定義された関数を呼び出します。これらの手順を実装する 1 つの方法を次に示します。
#include "get_cpuid_v1_lix64.h" void _CPUID(CPUIDinfo *info, const unsigned int func, const unsigned int subfunc) { get_cpuid_info_v1(info, func, subfunc); } typedef unsigned int DWORD; int _rdrand_check_support() { CPUIDinfo info; int got_intel_cpu=0; _CPUID(&info,0,0); if(memcmp((char *)(&info.EBX), "Genu", 4) == 0 && memcmp((char *)(&info.EDX), "ineI", 4) == 0 && memcmp((char *)(&info.ECX), "ntel", 4) == 0) { got_intel_cpu = 1; } if (got_intel_cpu) { _CPUID(&info,1,0); if ((info.ECX & 0x40000000)==0x40000000) return 1; } return 0; }
コードサンプル 3: get_cpuid_info_v1
を呼び出して RDRAND のサポートを確認
このサンプルの最初の _CPUID
呼び出しの後、コードは現在のプロセッサーがインテル製かどうかを確認します。2 回目の _CPUID
呼び出しの後、コードは RDRAND ビットを確認します。別の製造元がこのビット (ビット 30) を異なる目的に使用している場合、製造元を確認することが重要です。
4.1 RDRAND を使用したランダムな値の取得
CPUID を使用して RDRAND のサポートを確認できたら、RDRAND 命令を呼び出して 16 ビット、32 ビット、または 64 ビットの乱数 (整数) を取得することができます。この命令はプロセッサーのすべての権限レベルで利用できるため、システム・ソフトウェアやアプリケーションで RDRAND を自由に呼び出すことができます。
『Intel® 64 and IA-32 Architectures Software Developer’s Manual Vol 2B / May 2012』では、RDRAND 命令の使用法を次のように説明しています。
オペコード/ 命令 |
命令オペランドのエンコード | 64/32 ビット・モードのサポート | CPUID 機能フラグ | 説明 |
---|---|---|---|---|
0F C7 /6 RDRAND r16 |
ModRM:r/m(w) |
V/V |
RDRAND |
16 ビットの乱数を読み取り、デスティネーション・レジスターに格納します。 |
0F C7 /6 RDRAND r32 |
ModRM:r/m(w) |
V/V |
RDRAND |
32 ビットの乱数を読み取り、デスティネーション・レジスターに格納します。 |
REX.W + 0F C7 /6 RDRAND r64 |
ModRM:r/m(w) |
V/I |
RDRAND |
64 ビットの乱数を読み取り、デスティネーション・レジスターに格納します。 |
表 2: RDRAND 命令レファレンス
ユーザーは、乱数が格納されるデスティネーション・レジスターを単一オペランドとして、この命令を呼び出します。このレジスターは汎用レジスターでなければならず、レジスターのサイズ (16 ビット、32 ビット、または 64 ビット) によって返される乱数のサイズが決まる点に注意してください。
RDRAND 命令を呼び出した後、呼び出し元はキャリーフラグ (CF) を調べて乱数が RDRAND 命令実行時に利用可能だったかどうか確認する必要があります。CF 値 1 は、乱数が利用可能で、呼び出しで指定されたデスティネーション・レジスターに格納されたことを示します。CF 値 0 は、乱数が利用不可だったことを示します。この場合、デスティネーション・レジスターの値も 0 になります。
乱数の利用可否の指標としてデスティネーション・レジスターの値 0 を使用しないように注意してください。乱数の利用可否の指標には CF を使用します。
キャリーフラグの値 | 結果 |
---|---|
CF = 1 |
デスティネーション・レジスターは有効です。実行時に非ゼロの乱数を利用可能です。結果はレジスターに格納されます。 |
CF = 0 |
デスティネーション・レジスターはすべて 0 に設定されます。実行時に乱数は利用できません。リトライされることがあります。 |
表 3: キャリーフラグ (CF) の結果と意味
4.1.1 単純な RDRAND の呼び出し
RDRAND 命令の呼び出しの時点で乱数が利用できない可能性は、システムやアプリケーション API 定義で重要な意味を持ちます。多くの乱数関数は次のように非常に単純に定義されます。
unsigned int GetRandom()
ところが、RDRAND を使用するには、CF フラグ値に基づいて起こりえる結果を適切に管理するラッパー関数が必要です。
例えば、呼び出しルーチンに直接、命令の結果を単純に渡す制御アプローチが考えられます。このようなアプローチでは関数のシグネチャーは次の形式になります。
int rdrand(unsigned int *therand)
このアプローチでは、関数の戻り値が、RDRAND 命令の呼び出し結果を示すフラグになります。1 の場合、参照渡しの変数に使用可能な乱数が格納されます。0 の場合、呼び出し元は変数に割り当てられた値が使用できないと判断します。このアプローチの利点は、呼び出しの結果に基づいて処理方法を決定するオプションが呼び出し元に提示される点です。
コードサンプル 4、5、6 は、インライン・アセンブリーを使用して、このアプローチを RDRAND の 16 ビット、32 ビット、および 64 ビットの呼び出しに実装する方法を示しています。
int _rdrand16_step(unsigned short int *therand) { unsigned short int foo; int cf_error_status; asm("\n\ rdrand %%ax;\n\ mov $1,%%edx;\n\ cmovae %%ax,%%dx;\n\ mov %%edx,%1;\n\ mov %%ax, %0;":"=r"(foo),"=r"(cf_error_status)::"%ax","%dx"); *therand = foo; return cf_error_status; }
コードサンプル 4: 16 ビットの乱数用の単純な RDRAND 呼び出し
int _rdrand32_step(unsigned int *therand) { int foo; int cf_error_status; asm("\n\ rdrand %%eax;\n\ mov $1,%%edx;\n\ cmovae %%eax,%%edx;\n\ mov %%edx,%1;\n\ mov %%eax,%0;":"=r"(foo),"=r"(cf_error_status)::"%eax","%edx"); *therand = foo; return cf_error_status; }
コードサンプル 5: 32 ビットの乱数用の単純な RDRAND 呼び出し
int _rdrand64_step(unsigned long long int *therand) { unsigned long long int foo; int cf_error_status; asm("\n\ rdrand %%rax;\n\ mov $1,%%edx;\n\ cmovae %%rax,%%rdx;\n\ mov %%edx,%1;\n\ mov %%rax, %0;":"=r"(foo),"=r"(cf_error_status)::"%rax","%rdx"); *therand = foo; return cf_error_status; }
コードサンプル 6: 64 ビットの乱数用の単純な RDRAND 呼び出し
4.1.2 RDRAND リトライループ
RDRAND 実行時に利用できない乱数を制御する別のアプローチは、リトライループを構成することです。このアプローチでは、別途引数を使用することで、失敗値を返す前にリトライする最大数を呼び出し元に指定します。
int rdrand(unsigned int retry_limit, unsigned int *therand)
関数の成功または失敗は戻り値によって示され、乱数は (成功を仮定して) 参照変数により呼び出し元に渡されます。
コードサンプル 7 は、前のセクションの関数を基本的なプリミティブとして使用する 32 ビット乱数値の実装を示しています。
int _rdrand_get_uint_retry(unsigned int retry_limit, unsigned int *dest) { int success; int count; unsigned int therand; count = 0; do { success=_rdrand32_step(&therand); } while((success == 0) && (count++ < retry_limit)); if (success == 1) { *dest = therand; return 1; } else { return 0; } }
コードサンプル 7: リトライループを使用した 32 ビット RDRAND の呼び出し
4.2 任意のサイズのデータ・オブジェクトの初期化
RNG ライブラリー内の一般的な乱数関数は以下のようになります。
int rdrand_get_n_bytes(unsigned int n, unsigned char *dest)
この関数では、任意のサイズのデータ・オブジェクトがランダムなバイトで初期化されます。サイズは変数 n で指定され、データ・オブジェクトは char または void へのポインターとして渡されます。
この関数を実装するには、ループ制御構造と、以前に示された rdrand64_step()
関数または rdrand32_step()
関数の反復呼び出しが必要です。最初に rdrand32_step()
を使用して乱数値を unsigned int の配列に格納します。
int rdrand_get_n_uints(int n, unsigned int *dest) { int dwords; int i; unsigned int drand; int success; int total_uints; total_uints = 0; for (i=0; i < dwords; i++) { if (_rdrand32_step(&drand)) { *dest = drand; dest++; total_uints++; } else { i = dwords; } } return total_uints; }
コードサンプル 8: RDRAND を使用して任意のサイズのオブジェクトを初期化
関数は割り当てられている unsigned int 値の数を返します。呼び出し元は、要求した数に対するこの値を確認して、割り当てが成功したかどうかを判断します。また、リトライループを使用して乱数が利用不可である場合の処理など、別の実装も可能です。
次の例では、rdrand32_step()
の代わりに rdrand64_step()
を使用することで、RDRAND 呼び出しの回数を半分にしています。
int rdrand_get_n_uints(int n, unsigned int *dest) { int qwords; int i; unsigned long int qrand; int success; int total_uints; unsigned long int *qptr; total_uints = 0; qptr = (unsigned long int*)dest; qwords = n/2; for (i=0; i < qwords; i++) { if (_rdrand64_step(&qrand)) { *qptr = qrand; qptr++; total_uints+=2; } else { i = qwords; } } return total_uints; }
コードサンプル 9: RDRAND を使用して任意のサイズのオブジェクトを初期化
最後に、ループ制御構造と rdrand64_step()
を使用して乱数をバイト配列に格納する方法を示します。
int _rdrand_get_bytes_step(unsigned int n, unsigned char *dest) { unsigned char *start; unsigned char *residualstart; unsigned long long int *blockstart; unsigned int count; unsigned int residual; unsigned int startlen; unsigned long long int i; unsigned long long int temprand; unsigned int length; /* デスティネーション・バッファーの 64 ビットでアラインされている最初のブロックのアドレスを計算 */ start = dest; if (((unsigned long int)start % (unsigned long int)8) == 0) { blockstart = (unsigned long long int *)start; count = n; startlen = 0; } else { blockstart = (unsigned long long int *)(((unsigned long long int)start & ~(unsigned long long int)7)+(unsigned long long int)8); count = n - (8 - (unsigned int)((unsigned long long int)start % 8)); startlen = (unsigned int)((unsigned long long int)blockstart - (unsigned long long int)start); } /* 64 ビットのブロック数と残りのバイト数を計算 */ residual = count % 8; length = count >> 3; if (residual != 0) { residualstart = (unsigned char *)(blockstart + length); } /* 残差で使用する一時乱数を取得;リトライに失敗した場合は終了 */ if (startlen > 0) { if (_rdrand_get_n_qints_retry(1, 10, (void *)&temprand) == 0) return 0; } /* アラインされていない最初のブロックを処理 */ for (i = 0; i < startlen; i++) { start[i] = (unsigned char)(temprand & 0xff); temprand = temprand >> 8; } /* 中央のアラインされているブロックを処理; リトライに失敗した場合は終了 */ if (_rdrand_get_n_qints_retry(length, 10, (void *)(blockstart)) == 0) return 0; /* アラインされていない最後のブロックを処理 */ if (residual > 0) { if (_rdrand_get_n_qints_retry(1, 10, (void *)&temprand) == 0) return 0; for (i = 0; i < residual; i++) { residualstart[i] = (unsigned char)(temprand & 0xff); temprand = temprand >> 8; } } return 1; }
コードサンプル 10: RDRAND を使用して任意のサイズのオブジェクトを初期化
4.3 ライブラリー API の推奨
RDRAND を別のアプリケーションで利用可能にするライブラリー API は、2 つのレベルで処理を行います。最初に、ライブラリーは、16 ビット、32 ビット、または 64 ビットの乱数値を取得する RDRAND を呼び出す低水準のラッパーを提供します。実行時の乱数値の利用可否を示す CF フラグ値の結果は、呼び出し元に直接返されます。
int _rdrand_u16_step(unsigned short int *); int _rdrand_u32_step(unsigned int *); int _rdrand_u64_step(unsigned __int64 *);
次に、ライブラリーは、さまざまな RDRAND 呼び出しを管理する高水準の関数を提供します。例えば、次の関数は、リトライループを使用して乱数値が利用不可なケースを処理します。
int _rdrand_get_uint_retry(unsigned int retry_limit, unsigned int *dest);
任意のサイズとタイプの配列や他のオブジェクトを使用して RDRAND の複数の呼び出しを制御する関数もあります。
int _rdrand_get_rand_step(unsigned int n, void *dest); int _rdrand_get_rand_step_retry(unsigned int n, unsigned int retry_limit, void *dest);
4.4 DBRG のシード変更の保証
DRNG は、乱数の高性能なソースとして高速かつスケーラブルで、アプリケーションやオペレーティング・システムの RNG ライブラリーの基礎となる、乱数値の唯一のソースとして直接使用可能です。自身のソフトウェア PRNG のシード作成やシード変更に DRNG を使用したいと考えるソフトウェア・ベンダーもあるでしょう。規格に準拠するために、RDRAND によって返された値が DRNG 内のエントロピー・サンプルを反映するという絶対的な保証のために DRNG が必要だと考えるソフトウェア・ベンダーもあるでしょう。
セクション 3.2.3 で述べたように、DRNG は、決定論的乱数ビット・ジェネレーター (DRBG) を利用して品質改善されたエントロピー・サンプルを大きなセットの乱数に「広げ」、ハードウェア・モジュールで利用可能な乱数の量を増やします。DRBG は、シードをいつ変更するか自主的に決定します。RDRAND の呼び出し元は、シードが変更されたことは分かりますが、シードがいつ変更されるか予測することはできません。サイズが 128 ビットで、64 ビットの乱数を 2 つ提供するサンプルの実装では、シードあたりのサンプル数は 511 が上限になります。実際には、DRBG は頻繁にシード変更を行います。RDRAND で最大サンプル数を要求するかなり前にシード変更が行われることもあります。
DRBG がシード変更を行うことを保証する RDRAND 呼び出しを構築するアプローチは 2 つあります。
- 1022 を超える 64 ビット RDRAND を実行することで、DRBG の上限を超えて RDRAND を反復実行する。
- 反復ごとに 10 マイクロ秒待機して、32 の RDRAND 呼び出しを反復実行する。
後者のアプローチは、DRBG がアイドル中に積極的にシード変更を行うため、シード変更を強制的に行う効果があります。
下記のコードサンプルは、後者のアプローチを用いて、返される乱数が前の関数呼び出しおよび後の関数呼び出しとは独立したエントロピー・サンプルに基づくことを保証しています。
/* CBC-MAC で 32 の 128 ビット値を遅延収集してシード変更が行われることを保証 */ /* 前方追跡と後方追跡に完全に耐える乱数値を生成; NIST SP800-90 のシード変更に準拠; FIPS 1402-2 準拠の SW DRBG */ int _rdrand_get_seed128_retry(unsigned int retry_limit, void *buffer) { unsigned char m[16]; unsigned char key[16]; unsigned char ffv[16]; /* 前方値を提供 */ unsigned char xored[16]; unsigned int i; for (i=0;i < 16;i++) { key[i]=(unsigned char)i; ffv[i]=0; } for (i=0; i < 32; i++) { usleep(10); if (_rdrand_get_n_uints_retry(2,retry_limit,(unsigned long long int*)m) == 0) return 0; xor_128(m,ffv,xored); aes128k128d(key,xored,ffv); } for (i=0;i < 16;i++) ((unsigned char *)buffer)[i] = ffv[i]; return 1; }
多くの AES ライブラリー実装に含まれる 2 つの関数 xor_128()
と aes128k128d()
の使用に注意してください。複数の RDRAND 呼び出しから収集された乱数データは、セキュアなソフトウェア PRNG でシードとして使用するのに適した単一の 128 ビットの値を生成するように、適切な暗号関数を使用して組み合わせるべきです。ここで、xor_128 ()
および aes128k128d()
はどちらも、AES の AES-CBC-MAC モードを実装します。
5 参考文献 (英語)
[1] Makoto Matsumoto and Takuji Nishimura, (1998). Mersenne Twister: A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number Generator. ACM Transactions on Modeling and Computer Simulation, Vol. 8, No. 1, January 1998. [2] Z. Gutterman, B. Pinkas, and T. Reinman. (March, 2006). Analysis of the Linux Random Number Generator. http://www.pinkas.net/PAPERS/gpr06.pdf[3] CVE-2008-0166 (http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-0166)
[4] Information Processing Standard Publication 197, Nov 26th 2001, Specification for the Advanced Encryption Standard (AES) http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf.
[5] SP800-90 reference is ‘NIST Special Publication 800-90, Recommendation for Random Number Generation Using Deterministic Random Bit Generators (Revised), March 2007’
[6] NIST Special Publication 800-38A, Recommendation for Block Cipher Modes of Operation,http://csrc.nist.gov/publications/nistpubs/800-38a/addendum-to-nist_sp800-38A.pdf [8]『Intel® Processor Identification and the CPUID Instruction April 2012』(http://www.intel.com/content/www/us/en/processors/processor-identification-cpuid-instruction-note.html) [9] 『Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 2A and 2B: Instruction Set Reference / May 2012』著作権と商標について
本資料に掲載されている情報は、インテル製品の概要説明を目的としたものです。本資料は、明示されているか否かにかかわらず、また禁反言によるとよらずにかかわらず、いかなる知的財産権のライセンスを許諾するものではありません。製品に付属の売買契約書『Intel's Terms and Conditions of Sale』に規定されている場合を除き、インテルはいかなる責任を負うものではなく、またインテル製品の販売や使用に関する明示または黙示の保証 (特定目的への適合性、商品適格性、あらゆる特許権、著作権、その他知的財産権の非侵害性への保証を含む) に関してもいかなる責任も負いません。
インテルによる書面での合意がない限り、インテル製品は、その欠陥や故障によって人身事故が発生するようなアプリケーションでの使用を想定した設計は行われていません。
インテル製品は、予告なく仕様や説明が変更される場合があります。機能または命令の一覧で「留保」または「未定義」と記されているものがありますが、その「機能が存在しない」あるいは「性質が留保付である」という状態を設計の前提にしないでください。これらの項目は、インテルが将来のために留保しているものです。インテルが将来これらの項目を定義したことにより、衝突が生じたり互換性が失われたりしても、インテルは一切責任を負いません。この情報は予告なく変更されることがあります。この情報だけに基づいて設計を最終的なものとしないでください。
本資料で説明されている製品には、エラッタと呼ばれる設計上の不具合が含まれている可能性があり、公表されている仕様とは異なる動作をする場合があります。現在確認済みのエラッタについては、インテルまでお問い合わせください。
最新の仕様をご希望の場合や製品をご注文の場合は、お近くのインテルの営業所または販売代理店にお問い合わせください。
本資料で紹介されている資料番号付きのドキュメントや、インテルのその他の資料を入手するには、1-800-548-4725 (アメリカ合衆国) までご連絡いただくか、インテルの Web サイトを参照してください。
Intel、インテル、Intel ロゴは、アメリカ合衆国およびその他の国における Intel Corporation の商標です。
* その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。
© 2012 Intel Corporation. 無断での引用、転載を禁じます。
コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。