私は AES CUDA アプリケーションに取り組んでおり、GPU で ECB 暗号化を実行するカーネルを持っています。並列実行時にアルゴリズムのロジックが変更されないようにするために、NIST から提供された既知の入力テスト ベクトルを送信し、ホスト コードから出力を NIST から提供された既知のテスト ベクトル出力と比較します。8600M GT である NVIDIA GPU でこのテストを実行しました。これは Windows 7 で実行されており、ドライバーのバージョンは 3.0 です。このシナリオでは、すべてが完璧に機能し、アサートが成功します。
ここで、Quadro FX 770M でアプリケーションを実行すると、. 同じアプリケーションが起動され、同じテスト ベクトルが送信されますが、得られた結果は正しくなく、アサートは失敗します!!. これは、同じドライバー バージョンの Linux で実行されます。カーネルは 256 スレッドで実行されます。カーネル内で演算をスキップするために、事前に計算された 256 要素のルックアップ テーブルが使用されます。これらのテーブルはもともとグローバル メモリにロードされ、カーネルを起動する 256 のスレッドのうちの 1 つのスレッドが連携してルックアップ テーブルの 1 つの要素をロードし、その要素を共有メモリ内の新しいルックアップ テーブルに移動するため、アクセス レイテンシが減少します。
もともと、GPU 間のクロック速度の違いによる同期の問題について考えていました。そのため、スレッドが共有メモリにまだロードされていない値を使用していたり、何らかの形でまだ処理されていない値を使用していたりして、出力が混乱し、最終的に正しくなくなった可能性があります。
ここでは、既知のテスト ベクトルが宣言されているため、基本的には、カーネルのセットアップを担当する AES_set_encrption に送信されます。
void test_vectors ()
{
unsigned char testPlainText[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
unsigned char testKeyText[] = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77,0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4};
unsigned char testCipherText[] = {0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8};
unsigned char out[16] = {0x0};
//AES Encryption
AES_set_encrption( testPlainText, out, 16, (u32*)testKeyText);
//Display encrypted data
printf("\n GPU Encryption: ");
for (int i = 0; i < AES_BLOCK_SIZE; i++)
printf("%x", out[i]);
//Assert that the encrypted output is the same as the NIST testCipherText vector
assert (memcmp (out, testCipherText, 16) == 0);
}
ここでは、setup 関数がメモリの割り当て、カーネルの呼び出し、結果のホストへの送信を担当します。ホストに送り返す前に同期していることに注意してください。その時点ですべてが終了するはずです。これにより、問題はカーネル内にあると思われます..
__host__ double AES_set_encrption (... *input_data,...*output_data, .. input_length, ... ckey )
//Allocate memory in the device and copy the input buffer from the host to the GPU
CUDA_SAFE_CALL( cudaMalloc( (void **) &d_input_data,input_length ) );
CUDA_SAFE_CALL( cudaMemcpy( (void*)d_input_data, (void*)input_data, input_length, cudaMemcpyHostToDevice ) );
dim3 dimGrid(1);
dim3 dimBlock(THREAD_X,THREAD_Y); // THREAD_X = 4 & THREAD_Y = 64
AES_encrypt<<<dimGrid,dimBlock>>>(d_input_data);
cudaThreadSynchronize();
//Copy the data processed by the GPU back to the host
cudaMemcpy(output_data, d_input_data, input_length, cudaMemcpyDeviceToHost);
//Free CUDA resources
CUDA_SAFE_CALL( cudaFree(d_input_data) );
}
最後に、カーネル内で一連の AES ラウンドを計算します。同期の問題はカーネル内にあると考えていたので、__syncthreads(); を設定しました。各ラウンドまたは計算操作の後、すべてのスレッドが同時に移動していることを確認して、計算されていない値が評価されないようにします..しかし、それでも問題は解決しませんでした..
正常に動作する 8600M GT GPU を使用した場合の出力は次のとおりです。
AES 256 ビットキー
NIST テスト ベクトル:
平文: 6bc1bee22e409f96e93d7e117393172a
キー: 603deb1015ca71be2b73aef0857d7781
暗号文: f3eed1bdb5d2a03c64b5a7e3db181f8
GPU 暗号化: f3eed1bdb5d2a03c64b5a7e3db181f8
テストのステータス: 合格
そして、Quadro FX 770M を使用して失敗した場合がこれです!!
AES 256 ビット キー NIST テスト ベクトル:
平文: 6bc1bee22e409f96e93d7e117393172a
キー: 603deb1015ca71be2b73aef0857d7781
暗号文: f3eed1bdb5d2a03c64b5a7e3db181f8
GPU 暗号化: c837204eb4c1063ed79c77946893b0
Generic assert memcmp (out, testCipherText, 16) == 0 はエラーをスローしました
テスト ステータス: 失敗
2 つの GPU が同じカーネルを処理しても異なる結果を計算する理由は何でしょうか? この問題を解決するためのヒントやトラブルシューティング、または手順を教えていただければ幸いです
前もって感謝します!!