Я работаю над приложением AES CUDA, и у меня есть ядро, которое выполняет шифрование ECB на графическом процессоре. Чтобы убедиться, что логика алгоритма не изменяется при параллельной работе, я отправляю известный входной тестовый вектор, предоставленный NIST, а затем из кода хоста сравниваю вывод с известным тестовым вектором, предоставленным NIST, с утверждением. Я провел этот тест на своем графическом процессоре NVIDIA, который представляет собой 8600M GT. Работает под Windows 7 и версия драйвера 3.0. В этом сценарии все работает идеально, и утверждение выполняется успешно.
Теперь, когда приложение запущено на Quadro FX 770M. Запускается одно и то же приложение, отправляются те же тестовые векторы, но полученный результат неверен, и утверждение не выполняется!!. Это работает в Linux с той же версией драйвера. Ядра выполняются 256 потоками. Внутри ядер и для пропуска арифметических операций используются предварительно вычисленные таблицы поиска из 256 элементов. Эти таблицы изначально загружаются в глобальную память, 1 поток из 256 потоков, запускающих ядро, совместно загружает 1 элемент таблицы поиска и перемещает этот элемент в новую таблицу поиска в разделяемой памяти, что снижает задержку доступа.
Первоначально я думал о проблемах с синхронизацией из-за различий в тактовой частоте между графическими процессорами. Так что, возможно, потоки использовали значения, которые еще не были загружены в разделяемую память, или каким-то образом значения, которые все еще не были обработаны, что приводило к путанице в выводе и, в конце концов, к неправильному результату.
Здесь объявляются известные тестовые векторы, поэтому в основном они отправляются в 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);
}
Здесь функция установки отвечает за выделение памяти, вызов ядра и отправку результатов обратно в шлюху. Обратите внимание, что я выполнил синхронизацию перед отправкой обратно на хост, поэтому в этот момент все должно быть завершено, что заставляет меня думать, что проблема в ядре.
__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, который работает нормально:
256-битный ключ AES
Тестовые векторы NIST:
Текст жалобы: 6bc1bee22e409f96e93d7e117393172a
Ключ: 603deb1015ca71be2b73aef0857d7781
Зашифрованный текст: f3eed1bdb5d2a03c64b5a7e3db181f8
Шифрование графического процессора: f3eed1bdb5d2a03c64b5a7e3db181f8
Статус теста: пройден
И вот когда я использую Quadro FX 770M и терпит неудачу!!
256-битный ключ AES NIST Test Vectors:
Текст жалобы: 6bc1bee22e409f96e93d7e117393172a
Ключ: 603deb1015ca71be2b73aef0857d7781
Зашифрованный текст: f3eed1bdb5d2a03c64b5a7e3db181f8
Шифрование графического процессора: c837204eb4c1063ed79c77946893b0
Общее утверждение memcmp (out, testCipherText, 16) == 0 выдало ошибку
Статус теста: не пройден
В чем может быть причина того, что 2 графических процессора вычисляют разные результаты, даже если они обрабатывают одни и те же ядра??? Я буду признателен за любую подсказку или устранение неполадок, которые любой из вас мог бы мне дать, или за любой шаг, чтобы решить эту проблему.
Заранее спасибо!!