大家好,我们是这是一件好事队,今天为大家分享第三代安全算法SHA3(Keccack核心)的硬件实现代码。
NIST在2012年评选出了最终的算法并确定了新的哈希函数标准。Keccak算法由于其较强的安全性和优秀的软硬件实现性能,最终成为最新一代的哈希函数标准。2015年8月NIST发布了最终的
SHA-3 算法标准《FIPS
PUB 202—SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions》。
SHA-3算法同样是一种迭代哈希函数,但是采用了更先进的海绵结构,海绵结构是由Bertoni等人提出的一种用于将输入数据流压缩为任意长度输出的函数架构, 可以分为吸收和挤压两个阶段(如图 3‑3)。图中pad表示输入消息填充规则,f表示用于处理固定长度消息的底层迭代函数,r表示消息分组长度,c表示冗余容量,其中b = r + c表示比特率,也是整个运算过程中处理的中间状态的位宽。
在SHA-3算法中,采用的填充规则被称为“pad10*1”,其中的星号表示需要填充 的“0”可以被省略或多次重复。具体规则是,在消息后添加单比特的“1”,中间添加多比特的“0”,最后再添加单比特的“1”,使填充后的消息长度是消息分组长度的整数倍。填充后的消息按照分组长度拆分为P1、P2...Pn多个消息块,在算法吸收阶段被分块吸收。
算法吸收阶段,是使用迭代函数f对中间状态进行置换的同时,将分组后的消息分多次进行吸收。在第一次吸收前,中间状态的初始值为全零,将其低r比特与第一块消息P1按位异或后,拼接上原状态的高c比特作为迭代函数的输入;第二次吸收时,将上一阶段输出中间状态的低r比特与第二块消息P2按位异或,之后拼接上一阶段输出中间状态的高c比特,作为下一次迭代函数的输入;以此类推,完成所有消息块的吸收。
在算法挤压阶段,根据最后所需消息摘要的长度确定挤压阶段需要调用迭代函数 的次数。由于SHA-3算法对消息摘要长度的要求都小于消息分组长度c,则SHA-3算法在挤压阶段不需要调用迭代函数,直接截取最后一次吸收后输出中间状态的低位, 就能得到最终的消息摘要。
根据SHA-3算法标准,中间状态长度固定为1600比特,并且为了方便定义迭代函数中的具体运算,中间状态需按照一个5x5x64的三维矩阵如图 进行组织。
每次调用迭代函数时,输入及输出状态到三维矩阵的映射关系,应该遵循以下公式: A [x,y,z]=S[64(x + 5y) + z] 根据SHA-3算法标准,每调用一次迭代函数需要进行24轮迭代运算,每一轮迭代运算又需要完成规定的五步迭代。五步迭代作为整个循环迭代过程中的核心运算,具体定义如下:
软件实现代码:
static const uint64_t KeccakF_RoundConstants[NROUNDS] =
{
(uint64_t)0x0000000000000001ULL,
(uint64_t)0x0000000000008082ULL,
(uint64_t)0x800000000000808aULL,
(uint64_t)0x8000000080008000ULL,
(uint64_t)0x000000000000808bULL,
(uint64_t)0x0000000080000001ULL,
(uint64_t)0x8000000080008081ULL,
(uint64_t)0x8000000000008009ULL,
(uint64_t)0x000000000000008aULL,
(uint64_t)0x0000000000000088ULL,
(uint64_t)0x0000000080008009ULL,
(uint64_t)0x000000008000000aULL,
(uint64_t)0x000000008000808bULL,
(uint64_t)0x800000000000008bULL,
(uint64_t)0x8000000000008089ULL,
(uint64_t)0x8000000000008003ULL,
(uint64_t)0x8000000000008002ULL,
(uint64_t)0x8000000000000080ULL,
(uint64_t)0x000000000000800aULL,
(uint64_t)0x800000008000000aULL,
(uint64_t)0x8000000080008081ULL,
(uint64_t)0x8000000000008080ULL,
(uint64_t)0x0000000080000001ULL,
(uint64_t)0x8000000080008008ULL
};
/*************************************************
* Name: KeccakF1600_StatePermute
*
* Description: The Keccak F1600 Permutation
*
* Arguments: - uint64_t * state: pointer to in/output Keccak state
**************************************************/
void KeccakF1600_StatePermute(uint64_t * state)
{
int round;
uint64_t Aba, Abe, Abi, Abo, Abu;
uint64_t Aga, Age, Agi, Ago, Agu;
uint64_t Aka, Ake, Aki, Ako, Aku;
uint64_t Ama, Ame, Ami, Amo, Amu;
uint64_t Asa, Ase, Asi, Aso, Asu;
uint64_t BCa, BCe, BCi, BCo, BCu;
uint64_t Da, De, Di, Do, Du;
uint64_t Eba, Ebe, Ebi, Ebo, Ebu;
uint64_t Ega, Ege, Egi, Ego, Egu;
uint64_t Eka, Eke, Eki, Eko, Eku;
uint64_t Ema, Eme, Emi, Emo, Emu;
uint64_t Esa, Ese, Esi, Eso, Esu;
//printf("\n����\n");
for(int i=0;i<25;i++)
{
//printf("%llx\n",state[i]);
}
//copyFromState(A, state)
Aba = state[ 0];
Abe = state[ 1];
Abi = state[ 2];
Abo = state[ 3];
Abu = state[ 4];
Aga = state[ 5];
Age = state[ 6];
Agi = state[ 7];
Ago = state[ 8];
Agu = state[ 9];
Aka = state[10];
Ake = state[11];
Aki = state[12];
Ako = state[13];
Aku = state[14];
Ama = state[15];
Ame = state[16];
Ami = state[17];
Amo = state[18];
Amu = state[19];
Asa = state[20];
Ase = state[21];
Asi = state[22];
Aso = state[23];
Asu = state[24];
for( round = 0; round < NROUNDS; round += 2 )
{
// prepareTheta
BCa = Aba^Aga^Aka^Ama^Asa;
BCe = Abe^Age^Ake^Ame^Ase;
BCi = Abi^Agi^Aki^Ami^Asi;
BCo = Abo^Ago^Ako^Amo^Aso;
BCu = Abu^Agu^Aku^Amu^Asu;
//thetaRhoPiChiIotaPrepareTheta(round , A, E)
Da = BCu^ROL(BCe, 1);
De = BCa^ROL(BCi, 1);
Di = BCe^ROL(BCo, 1);
Do = BCi^ROL(BCu, 1);
Du = BCo^ROL(BCa, 1);
Aba ^= Da;
BCa = Aba;
Age ^= De;
BCe = ROL(Age, 44);
Aki ^= Di;
BCi = ROL(Aki, 43);
Amo ^= Do;
BCo = ROL(Amo, 21);
Asu ^= Du;
BCu = ROL(Asu, 14);
Eba = BCa ^((~BCe)& BCi );
Eba ^= (uint64_t)KeccakF_RoundConstants[round];
Ebe = BCe ^((~BCi)& BCo );
Ebi = BCi ^((~BCo)& BCu );
Ebo = BCo ^((~BCu)& BCa );
Ebu = BCu ^((~BCa)& BCe );
Abo ^= Do;
BCa = ROL(Abo, 28);
Agu ^= Du;
BCe = ROL(Agu, 20);
Aka ^= Da;
BCi = ROL(Aka, 3);
Ame ^= De;
BCo = ROL(Ame, 45);
Asi ^= Di;
BCu = ROL(Asi, 61);
Ega = BCa ^((~BCe)& BCi );
Ege = BCe ^((~BCi)& BCo );
Egi = BCi ^((~BCo)& BCu );
Ego = BCo ^((~BCu)& BCa );
Egu = BCu ^((~BCa)& BCe );
Abe ^= De;
BCa = ROL(Abe, 1);
Agi ^= Di;
BCe = ROL(Agi, 6);
Ako ^= Do;
BCi = ROL(Ako, 25);
Amu ^= Du;
BCo = ROL(Amu, 8);
Asa ^= Da;
BCu = ROL(Asa, 18);
Eka = BCa ^((~BCe)& BCi );
Eke = BCe ^((~BCi)& BCo );
Eki = BCi ^((~BCo)& BCu );
Eko = BCo ^((~BCu)& BCa );
Eku = BCu ^((~BCa)& BCe );
Abu ^= Du;
BCa = ROL(Abu, 27);
Aga ^= Da;
BCe = ROL(Aga, 36);
Ake ^= De;
BCi = ROL(Ake, 10);
Ami ^= Di;
BCo = ROL(Ami, 15);
Aso ^= Do;
BCu = ROL(Aso, 56);
Ema = BCa ^((~BCe)& BCi );
Eme = BCe ^((~BCi)& BCo );
Emi = BCi ^((~BCo)& BCu );
Emo = BCo ^((~BCu)& BCa );
Emu = BCu ^((~BCa)& BCe );
Abi ^= Di;
BCa = ROL(Abi, 62);
Ago ^= Do;
BCe = ROL(Ago, 55);
Aku ^= Du;
BCi = ROL(Aku, 39);
Ama ^= Da;
BCo = ROL(Ama, 41);
Ase ^= De;
BCu = ROL(Ase, 2);
Esa = BCa ^((~BCe)& BCi );
Ese = BCe ^((~BCi)& BCo );
Esi = BCi ^((~BCo)& BCu );
Eso = BCo ^((~BCu)& BCa );
Esu = BCu ^((~BCa)& BCe );
// prepareTheta
BCa = Eba^Ega^Eka^Ema^Esa;
BCe = Ebe^Ege^Eke^Eme^Ese;
BCi = Ebi^Egi^Eki^Emi^Esi;
BCo = Ebo^Ego^Eko^Emo^Eso;
BCu = Ebu^Egu^Eku^Emu^Esu;
//thetaRhoPiChiIotaPrepareTheta(round+1, E, A)
Da = BCu^ROL(BCe, 1);
De = BCa^ROL(BCi, 1);
Di = BCe^ROL(BCo, 1);
Do = BCi^ROL(BCu, 1);
Du = BCo^ROL(BCa, 1);
Eba ^= Da;
BCa = Eba;
Ege ^= De;
BCe = ROL(Ege, 44);
Eki ^= Di;
BCi = ROL(Eki, 43);
Emo ^= Do;
BCo = ROL(Emo, 21);
Esu ^= Du;
BCu = ROL(Esu, 14);
Aba = BCa ^((~BCe)& BCi );
Aba ^= (uint64_t)KeccakF_RoundConstants[round+1];
Abe = BCe ^((~BCi)& BCo );
Abi = BCi ^((~BCo)& BCu );
Abo = BCo ^((~BCu)& BCa );
Abu = BCu ^((~BCa)& BCe );
Ebo ^= Do;
BCa = ROL(Ebo, 28);
Egu ^= Du;
BCe = ROL(Egu, 20);
Eka ^= Da;
BCi = ROL(Eka, 3);
Eme ^= De;
BCo = ROL(Eme, 45);
Esi ^= Di;
BCu = ROL(Esi, 61);
Aga = BCa ^((~BCe)& BCi );
Age = BCe ^((~BCi)& BCo );
Agi = BCi ^((~BCo)& BCu );
Ago = BCo ^((~BCu)& BCa );
Agu = BCu ^((~BCa)& BCe );
Ebe ^= De;
BCa = ROL(Ebe, 1);
Egi ^= Di;
BCe = ROL(Egi, 6);
Eko ^= Do;
BCi = ROL(Eko, 25);
Emu ^= Du;
BCo = ROL(Emu, 8);
Esa ^= Da;
BCu = ROL(Esa, 18);
Aka = BCa ^((~BCe)& BCi );
Ake = BCe ^((~BCi)& BCo );
Aki = BCi ^((~BCo)& BCu );
Ako = BCo ^((~BCu)& BCa );
Aku = BCu ^((~BCa)& BCe );
Ebu ^= Du;
BCa = ROL(Ebu, 27);
Ega ^= Da;
BCe = ROL(Ega, 36);
Eke ^= De;
BCi = ROL(Eke, 10);
Emi ^= Di;
BCo = ROL(Emi, 15);
Eso ^= Do;
BCu = ROL(Eso, 56);
Ama = BCa ^((~BCe)& BCi );
Ame = BCe ^((~BCi)& BCo );
Ami = BCi ^((~BCo)& BCu );
Amo = BCo ^((~BCu)& BCa );
Amu = BCu ^((~BCa)& BCe );
Ebi ^= Di;
BCa = ROL(Ebi, 62);
Ego ^= Do;
BCe = ROL(Ego, 55);
Eku ^= Du;
BCi = ROL(Eku, 39);
Ema ^= Da;
BCo = ROL(Ema, 41);
Ese ^= De;
BCu = ROL(Ese, 2);
Asa = BCa ^((~BCe)& BCi );
Ase = BCe ^((~BCi)& BCo );
Asi = BCi ^((~BCo)& BCu );
Aso = BCo ^((~BCu)& BCa );
Asu = BCu ^((~BCa)& BCe );
}
//copyToState(state, A)
state[ 0] = Aba;
state[ 1] = Abe;
state[ 2] = Abi;
state[ 3] = Abo;
state[ 4] = Abu;
state[ 5] = Aga;
state[ 6] = Age;
state[ 7] = Agi;
state[ 8] = Ago;
state[ 9] = Agu;
state[10] = Aka;
state[11] = Ake;
state[12] = Aki;
state[13] = Ako;
state[14] = Aku;
state[15] = Ama;
state[16] = Ame;
state[17] = Ami;
state[18] = Amo;
state[19] = Amu;
state[20] = Asa;
state[21] = Ase;
state[22] = Asi;
state[23] = Aso;
state[24] = Asu;
#undef round
}
硬件实现代码:
module KeccakF1600_StatePermute(clk,start,rst,init,Sin,busy,valid,Sout);
parameter b = 1600;
input [0:b-1]Sin;
input clk,start,rst,init;
output busy,valid;
output [0:b-1]Sout;
wire [0:63]Statein[5][5];
logic valid;
logic busy;
logic [4:0] cycle_num;
logic [0:63]product[5][5];
wire co;
// S->A转化
genvar x,y,z;
generate
for(x=0;x<5;x++)
begin
for(y=0;y<5;y++)
begin
for(z=0;z<64;z++)
begin
assign Statein[x][y][z] = Sin [64 * (5*y + x) + z] ;
end
end
end
endgenerate
wire [0:63]A[5][5];
assign A=(start&~busy)? Statein:product;
//theta *********************//
//theta1
wire [0:63]C[5];
generate
for(x=0;x<5;x++)
begin
for(z=0;z<64;z++)
begin
assign C[x][z]=A[x][0][z]^A[x][1][z]^A[x][2][z]^A[x][3][z]^A[x][4][z];
end
end
endgenerate
//theta2 可能要改
wire [0:63]D[5];
generate
for(x=0;x<5;x++)
begin
for(z=0;z<64;z++)
begin
assign D[x][z]= C[(x+4)%5][z] ^ C[(x+1)%5][(z+1)%64];
end
end
endgenerate
//theta 3
wire [0:63]theta_out [5][5];
generate
for(x=0;x<5;x++)
begin
for(z=0;z<64;z++)
begin
for(y=0;y<5;y++)
begin
assign theta_out[x][y][z]=A[x][y][z]^D[x][z];
end
end
end
endgenerate
//*********************//
//rou ****************//
wire [0:63]rou_out[5][5];
assign rou_out[0][0]={theta_out[0][0]};
assign rou_out[1][0]={theta_out[1][0][ 1:63],theta_out[1][0][ 0]};
assign rou_out[2][0]={theta_out[2][0][62:63],theta_out[2][0][0:61]};
assign rou_out[3][0]={theta_out[3][0][28:63],theta_out[3][0][0:27]};
assign rou_out[4][0]={theta_out[4][0][27:63],theta_out[4][0][0:26]};
assign rou_out[0][1]={theta_out[0][1][36:63],theta_out[0][1][0:35]};
assign rou_out[1][1]={theta_out[1][1][44:63],theta_out[1][1][0:43]};
assign rou_out[2][1]={theta_out[2][1][ 6:63],theta_out[2][1][0: 5]};
assign rou_out[3][1]={theta_out[3][1][55:63],theta_out[3][1][0:54]};
assign rou_out[4][1]={theta_out[4][1][20:63],theta_out[4][1][0:19]};
assign rou_out[0][2]={theta_out[0][2][ 3:63],theta_out[0][2][0: 2]};
assign rou_out[1][2]={theta_out[1][2][10:63],theta_out[1][2][0: 9]};
assign rou_out[2][2]={theta_out[2][2][43:63],theta_out[2][2][0:42]};
assign rou_out[3][2]={theta_out[3][2][25:63],theta_out[3][2][0:24]};
assign rou_out[4][2]={theta_out[4][2][39:63],theta_out[4][2][0:38]};
assign rou_out[0][3]={theta_out[0][3][41:63],theta_out[0][3][0:40]};
assign rou_out[1][3]={theta_out[1][3][45:63],theta_out[1][3][0:44]};
assign rou_out[2][3]={theta_out[2][3][15:63],theta_out[2][3][0:14]};
assign rou_out[3][3]={theta_out[3][3][21:63],theta_out[3][3][0:20]};
assign rou_out[4][3]={theta_out[4][3][ 8:63],theta_out[4][3][0: 7]};
assign rou_out[0][4]={theta_out[0][4][18:63],theta_out[0][4][0:17]};
assign rou_out[1][4]={theta_out[1][4][ 2:63],theta_out[1][4][0: 1]};
assign rou_out[2][4]={theta_out[2][4][61:63],theta_out[2][4][0:60]};
assign rou_out[3][4]={theta_out[3][4][56:63],theta_out[3][4][0:55]};
assign rou_out[4][4]={theta_out[4][4][14:63],theta_out[4][4][0:13]};
//*********************//
//pai ****************// 可能要改
wire [0:63]pai_out[5][5];
generate
for(x=0;x<5;x++)
begin
for(y=0;y<5;y++)
begin
assign pai_out[x][y]=rou_out[(x+3*y)%5][x];
end
end
endgenerate
//********************//
//kai ***************// 可能要改
wire [0:63]kai_out[5][5];
generate
for(x=0;x<5;x++)
begin
for(y=0;y<5;y++)
begin
for(z=0;z<64;z++)
begin
assign kai_out[x][y][z]=pai_out[x][y][z]^(~pai_out[(x+1)%5][y][z] & pai_out[(x+2)%5][y][z]);
end
end
end
endgenerate
//********************//
//lota **************//
wire [0:63]lota_out[5][5];
logic [6:0]RC;
//轮数
always@(posedge clk)
begin
if(rst) cycle_num<=0;
else if(co) cycle_num<=0;
else if(busy|start) cycle_num<=cycle_num+1;
else cycle_num<=0;
end
//busy
always@(posedge clk)
begin
if(rst) busy<=0;
else if(start&~busy) busy<=1;
else if(co) busy<=0;
end
//valid
assign co = (cycle_num==23);
always @(posedge clk) begin
if(rst) valid<=0;
else if(co) valid<=1;
else valid<=0;
end
//product
generate
for(x=0;x<5;x++)
begin
for(y=0;y<5;y++)
begin
always @(posedge clk)
begin
if(rst|(init&~busy)) product[x][y]<=64'h0;
else if(busy|start) product[x][y]<=lota_out[x][y];
end
end
end
endgenerate
//RC
always @(*)
begin
case (cycle_num)
5'D0:RC=7'H01;
5'D1:RC=7'H1A;
5'D2:RC=7'H5E;
5'D3:RC=7'H70;
5'D4:RC=7'H1F;
5'D5:RC=7'H21;
5'D6:RC=7'H79;
5'D7:RC=7'H55;
5'D8:RC=7'H0E;
5'D9:RC=7'H0C;
5'D10:RC=7'H35;
5'D11:RC=7'H26;
5'D12:RC=7'H3F;
5'D13:RC=7'H4F;
5'D14:RC=7'H5D;
5'D15:RC=7'H53;
5'D16:RC=7'H52;
5'D17:RC=7'H48;
5'D18:RC=7'H16;
5'D19:RC=7'H66;
5'D20:RC=7'H79;
5'D21:RC=7'H58;
5'D22:RC=7'H21;
5'D23:RC=7'H74;
default RC=7'H00;
endcase
end
generate
for(x=0;x<5;x++)
begin
for(y=1;y<5;y++)
begin
assign lota_out[x][y]=kai_out[x][y];
end
end
endgenerate
assign lota_out[1][0]=kai_out[1][0];
assign lota_out[2][0]=kai_out[2][0];
assign lota_out[3][0]=kai_out[3][0];
assign lota_out[4][0]=kai_out[4][0];
assign lota_out[0][0]={kai_out[0][0][ 0]^RC[6],kai_out[0][0][ 1:31],
kai_out[0][0][32]^RC[5],kai_out[0][0][33:47],
kai_out[0][0][48]^RC[4],kai_out[0][0][49:55],
kai_out[0][0][56]^RC[3],kai_out[0][0][57:59],
kai_out[0][0][60]^RC[2],kai_out[0][0][ 61],
kai_out[0][0][62]^RC[1],
kai_out[0][0][63]^RC[0]};
//********************//
assign Sout={product[0][0][0:63],product[1][0][0:63],product[2][0][0:63],product[3][0][0:63],product[4][0][0:63],
product[0][1][0:63],product[1][1][0:63],product[2][1][0:63],product[3][1][0:63],product[4][1][0:63],
product[0][2][0:63],product[1][2][0:63],product[2][2][0:63],product[3][2][0:63],product[4][2][0:63],
product[0][3][0:63],product[1][3][0:63],product[2][3][0:63],product[3][3][0:63],product[4][3][0:63],
product[0][4][0:63],product[1][4][0:63],product[2][4][0:63],product[3][4][0:63],product[4][4][0:63]};
endmodule