我一直在研究AES CUDA应用程序,我有一个在GPU上执行ECB加密的内核。为了确保在并行运行时不修改算法的逻辑,我发送NIST提供的已知输入测试向量,然后从主机代码将输出与NIST提供的已知测试向量输出与断言进行比较。 我在我的NVIDIA GPU上运行了这个测试,这是一个8600M GT。这是在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);
}
在这里,设置功能负责分配内存,调用内核并将结果发送回hos。请注意我在发送回主机之前已经进行了syncrhonize,所以此时应该完成一切,这让我觉得问题在内核中。
__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();在每轮或计算操作之后,确保所有线程同时移动,以便不评估未计算的值migth ..但仍然没有解决问题..
AES 256位密钥
NIST测试向量:
PlaintText:6bc1bee22e409f96e93d7e117393172a
Key:603deb1015ca71be2b73aef0857d7781
CipherText:f3eed1bdb5d2a03c64b5a7e3db181f8
GPU加密:f3eed1bdb5d2a03c64b5a7e3db181f8
测试状态:通过
AES 256位密钥 NIST测试向量:
PlaintText:6bc1bee22e409f96e93d7e117393172a
Key:603deb1015ca71be2b73aef0857d7781
CipherText:f3eed1bdb5d2a03c64b5a7e3db181f8
GPU加密:c837204eb4c1063ed79c77946893b0
通用断言memcmp(out,testCipherText,16)== 0抛出错误
测试状态:失败
即使处理相同的内核,2个GPU计算不同结果的原因可能是什么? 我将非常感谢您提供的任何暗示或疑难解答或任何步骤以解决此问题
提前致谢!!
答案 0 :(得分:1)
你使用双精度?你可能知道,但只是为了确定 - 我相信你使用的两张卡都是计算能力1.1,它不支持双精度。也许卡或平台以不同的方式转换为单精度......?谁知道?说实话,IEEE浮点偏差很明确,所以我很惊讶。