我是Gimli的作者之一。我们已经在C中拥有2个tweet(280个字符)的版本,但是我想看看它有多小。
Gimli(论文,网站)是一种高速,高安全级别的加密排列设计,将在2017年加密硬件和嵌入式系统大会(CHES)(9月25日至28日)上展出。
任务
像往常一样:用您选择的语言来实现Gimli的较小可用的实现。
它应该能够将384位(或48个字节,或12个无符号int ...)作为输入并返回(如果使用指针,则可以在适当位置进行修改)应用于这384位的Gimli结果。
允许从十进制,十六进制,八进制或二进制的输入转换。
潜在的极端情况
整数编码被假定为低端(例如,您可能已经拥有的)。
您可以重命名Gimli
为,G
但是它仍然必须是函数调用。
谁赢?
这是代码高尔夫球,因此最短的答案以字节为单位!标准规则当然适用。
下面提供了参考实现。
注意
引起了一些关注:
“嗨,帮派,请用其他语言免费实施我的程序,这样我就不必了”(致谢@jstnthms)
我的回答如下:
我可以轻松地用Java,C#,JS,Ocaml来完成它……这很有趣。目前,我们(Gimli团队)已在AVR,Cortex-M0,Cortex-M3 / M4,Neon,SSE,SSE展开,AVX,AVX2,VHDL和Python3上实现(并优化)。:)
关于金利
状态
Gimli将一轮回合应用于384位状态。状态表示为尺寸为3×4×32的平行六面体,或等效地表示为32位字的3×4矩阵。
每个回合是三个操作的序列:
- 非线性层,特别是应用于每列的96位SP盒;
- 在第二轮中,形成一个线性混合层;
- 在第四轮中,不断增加。
非线性层。
SP盒包含三个子操作:第一个单词和第二个单词的旋转;第二个单词的旋转。3输入非线性T函数;以及第一个和第三个单词的交换。
线性层。
线性层包含两个交换操作,即小交换和大交换。从第1轮开始,每4轮进行一次小交换。从第3轮开始,每4轮进行一次大掉期。
舍入常数。
Gimli有24发子弹,编号为24,23,...,1。当舍入数r为24、20、16、12、8、4时,我们将舍入常数(0x9e377900 XOR r)与第一个状态字进行异或。
C语言参考源
#include <stdint.h>
uint32_t rotate(uint32_t x, int bits)
{
if (bits == 0) return x;
return (x << bits) | (x >> (32 - bits));
}
extern void gimli(uint32_t *state)
{
int round;
int column;
uint32_t x;
uint32_t y;
uint32_t z;
for (round = 24; round > 0; --round)
{
for (column = 0; column < 4; ++column)
{
x = rotate(state[ column], 24);
y = rotate(state[4 + column], 9);
z = state[8 + column];
state[8 + column] = x ^ (z << 1) ^ ((y&z) << 2);
state[4 + column] = y ^ x ^ ((x|z) << 1);
state[column] = z ^ y ^ ((x&y) << 3);
}
if ((round & 3) == 0) { // small swap: pattern s...s...s... etc.
x = state[0];
state[0] = state[1];
state[1] = x;
x = state[2];
state[2] = state[3];
state[3] = x;
}
if ((round & 3) == 2) { // big swap: pattern ..S...S...S. etc.
x = state[0];
state[0] = state[2];
state[2] = x;
x = state[1];
state[1] = state[3];
state[3] = x;
}
if ((round & 3) == 0) { // add constant: pattern c...c...c... etc.
state[0] ^= (0x9e377900 | round);
}
}
}
C中的可推文版本
这可能不是最小的可用实现,但是我们希望有一个C标准版本(因此没有UB,并且在库中“可用”)。
#include<stdint.h>
#define P(V,W)x=V,V=W,W=x
void gimli(uint32_t*S){for(long r=24,c,x,y,z;r;--r%2?P(*S,S[1+y/2]),P(S[3],S[2-y/2]):0,*S^=y?0:0x9e377901+r)for(c=4;c--;y=r%4)x=S[c]<<24|S[c]>>8,y=S[c+4]<<9|S[c+4]>>23,z=S[c+8],S[c]=z^y^8*(x&y),S[c+4]=y^x^2*(x|z),S[c+8]=x^2*z^4*(y&z);}
测试向量
以下输入由生成
for (i = 0;i < 12;++i) x[i] = i * i * i + i * 0x9e3779b9;
和“印刷”值
for (i = 0;i < 12;++i) {
printf("%08x ",x[i])
if (i % 4 == 3) printf("\n");
}
从而:
00000000 9e3779ba 3c6ef37a daa66d46
78dde724 1715611a b54cdb2e 53845566
f1bbcfc8 8ff34a5a 2e2ac522 cc624026
应该返回:
ba11c85a 91bad119 380ce880 d24c2c68
3eceffea 277a921c 4f73a0bd da5a9cd8
84b673f0 34e52ff7 9e2bef49 f41bb8d6