我在GCM SP-800-38D文档here中为块(Alogrithm 1)的乘法建立了一个C代码。第11-12页。
完成代码后,我想知道是否有任何方法可以测试代码。您可以在我提供的代码下面找到附件。请注意,我使用24位块代替128位块,仅用于测试目的。如有必要,我将不胜感激。
void BLK_MUL (u8 *val_1,u8 *val_2, u8 *out_val)
{
u8 xdata R_val = 0xE1;
u8 xdata Z_val[3],V_val[3];
u8 mask_b = 0x80;
u16 i; u8 j;
bit rnd;
for(j=0;j<3;j++,++val_2)
{
Z_val[j]=0x00;
V_val[j]=*val_2;
}
for(i=0;i<24;i++)
{
if (*val_1 & mask_b)
{
for(j=0;j<3;j++)
Z_val[j]^=V_val[j];
}
if (!(V_val[2] & 0x01))
{//if LSB of V_val is 0
for(j=0;j<3;j++)
{ //V_val = rightshift(V_val)
if (j!=0)
if (V_val[2-j] & 0x01)
V_val[3-j] |= 0x80;
V_val[2-j]>>=1;
}
}
else
{//if LSB of V_val is 1
for(j=0;j<3;j++)
{//V_val = rightshift(V_val)
if (j!=0)
if (V_val[2-j] & 0x01)
V_val[3-j] |= 0x80;
V_val[2-j]>>=1;
}
V_val[0]^=R_val; //V_val = rightshift(V_val) ^ R
}
if(mask_b & 0x01) { val_1++; rnd=1;}
mask_b >>= 1;
if (rnd) { mask_b=0x80; rnd=0; }
}
STR_CPY(out_val,Z_val,3);
return ;
}
void main()
{
code unsigned char val_1[3] ={ 0x2b,0x7e,0x15 };
code unsigned char val_2[3] ={ 0x39,0x25,0x84 };
unsigned char out[3];
BLK_MUL (val_1,val_2,out);
return;
}
答案 0 :(得分:8)
在某些时候,您当然必须根据测试向量检查您的代码。但是,您可以执行相当多的测试而无需知道或计算任何测试向量。
首先,GF(2 ^ 128)中的乘法是可交换的。因此你可以计算 任何输入的BLK_MUL(val_1,val_2,out1)和BLK_MUL(val_2,val_1,out2)都应该得到相同的结果。由于您的代码使用val_1和val_2不同,这已经是一个非常好的测试。
然后你可以使用那个乘法是分配的,即。你可以测试一下 (x + y)* z =(x * z)+(y * z),(其中GF(2 ^ 128)中的加法是通过将两个值的相应字节一起计算得到的)。
最后,一旦你实现了整个字段GF(2 ^ 128),你也可以利用它 它的顺序是2 ^ 128-1。即如果你从值x开始然后将它平方128次,那么你应该得到x。
另外一些评论:
使用公式进行测试(仅使用测试向量)的优点是可以轻松运行大量测试。因为以这种方式添加测试相当容易,所以我经常使用稀疏输入进行一些简单的测试(例如,在输入中设置单个位) 第一。如果出现问题,那么这有助于快速识别错误。
您当前的代码使用临时变量作为结果。这确实是一个好主意,因为它可以确保复制安全。我认为一个好的单元测试也应该涵盖这个案例。 即你可能想要计算两次相同的结果:一次输入和输出指向不同的内存位置,一次输出与输入相同的内存。
此外,至少有一个其他答案谈到了优化。我想如果你 重构代码然后你应该寻找有意义的组件来重用,而不是 盲目地寻找看起来像代码片段。因为GF(2 ^ 128)当然是一个领域 在该领域中的加法和乘法是有意义的组成部分。另一个意义 component是多项式x的乘法(这是相当的 常用于加密)。
答案 1 :(得分:5)
答案 2 :(得分:3)
谢谢@jack和@emboss。根据jack的建议,我对该功能进行了测试,结果证明是正确的。希望这对其他人有用,但仍会欣赏任何建议和更正。 :)见下面的主要代码:
void main()
{
u8 j;
u8 val_1[3] ={ 0x2b,0x7e,0x15 };
u8 val_2[3] ={ 0x39,0x25,0x84 };
u8 val_3[3] ={ 0x23,0x71,0x25 };
u8 val_3_2[3]={ 0x23,0x71,0x25 };
u8 val_4[3] ={ 0x33,0x35,0x44 };
u8 val_5[3] ={ 0x2e,0x77,0x11 };
u8 out[3];
u8 out_1[3];
u8 out_2[3];
u8 out_3[3];
u8 out_4[3];
u8 out_5[3];
//PROOF X*Y = Y*X
BLK_MUL (val_1,val_2,out); //X*Y
BLK_MUL (val_2,val_1,out_1); //Y*X
//N.B: out == out_1
//PROOF (X+Y)*Z = (X*Z)+(Y*Z)
for(j=0;j<3;j++)
val_3[j]^=val_4[j]; //X = X+Y
BLK_MUL (val_3,val_5,out_2); //(X+Y)*Z
BLK_MUL (val_5,val_3,out_3); //Z*(X+Y)
//N.B: out_2 == out_3
BLK_MUL (val_3_2,val_5,out_4); //X*Z
BLK_MUL (val_4,val_5,out_5); //Y*Z
for(j=0;j<3;j++)
out_4[j]^=out_5[j]; //(X*Z)+(Y*Z)
//N.B: out_3=out_2=out_4
return;
}
答案 3 :(得分:3)
GF(2 ^ 128)的测试示例可在以下网址找到:PCLMULQDQ CPU instruction,第78页
答案 4 :(得分:2)
我不会评论它是否有效或如何测试,但我可以给你一些编码提示:
const
... x
和y
以及输出z
; R_val
应该只是一个常量,R
,mask_b
只是mask
,v_val
只是v
。进行这些更改后,您的代码将突然变得可读。u8
应该是uint8_t(来自stdint.h)或者只是unsigned char。Z_val
是多余的;只需使用输出参数z
(out_val)i
和j
应为int
rnd
是多余的 0x01
与1
相同 - 后者更具可读性。
if (!(V_val[2] & 0x01))
条款可以简化为:
v[2]>>=1; /* EDIT --- missed this out before */
for (j=1; j<3; j++)
{
if (v[2-j] & 1)
v[3-j] |= 0x80;
v[2-j] >>= 1;
}
if (v[2] & 1)
v[0] ^= R;
这个东西:
if(mask_b & 0x01) { val_1++; rnd=1;}
mask_b >>= 1;
if (rnd) { mask_b=0x80; rnd=0; }
可以简化为(重命名后)
if ((mask >>= 1) == 0)
{
x++;
mask = 0x80;
}
EDIT2(第一次编辑在上面的for循环之前添加了缺失行)
您有两个相同循环的副本,一个在if (!(v[2] & 1))
子句中,另一个在else
子句中。后者(else子句)也有一个v[0] ^= R;
。一份副本可以省略。此外,循环特别对待j == 0,这就是我从循环中提取它的原因(但在帖子中省略了它)。然后循环只有2个项目,j == 1和2.
您可以并且可能应该解开剩下的循环来获取:
v[2] >>= 1;
if (v[1] & 1) v[2] |= 0x80;
v[1] >>= 1;
if (v[0] & 1) v[1] |= 0x80;
v[0] >>= 1;
if (v[2] & 1) v[0] ^= R;
答案 5 :(得分:2)
你也有一个数学考虑尝试使用GF(2 ^ 128)代码GF(2 ^ 128)
常量“R_val = 0xE1”特定于GF(2 ^ 128)并反映不可约多项式的低阶指标
x^128 + x^7 + x^2 + x^1 + 1
这是GF(2 ^ 128)的流行同构的生成器,经常使用加密方式。
这相当于位向量(1 || 120“0”|| 10000111)。 (其中每个位反映多项式中出现的“x”的幂。)
低位(高位位128消耗平衡溢出位)以big-endian方式写入x87或以little-endian方式表示xE1。
然而对于GF(2 ^ 24),似乎不太可能,先验,
x^24 + x^7 + x^2 + x^1 + 1
是不可减少的(但我还没有测试过)
那么众所周知的是用于G(2 ^ 24)的良好,有效的不可约多项式?
根据表http://www.hpl.hp.com/techreports/98/HPL-98-135.pdf,GF(2 ^ 24)的最低/最简单的不可约多项式似乎是
x^24 + x^4 + x^3 + x^1 + 1
对应于位向量(1 || 16“0”|| 00011011)。
因此,再次因为高阶位消耗平衡溢出,正确的校正因子,你的R_val,用litle-endian方式写的将是R_val = 0xD8
希望你觉得这很有用。