%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Copyright: 2010 Integrated Sytems Laboratory, ETH Zurich
%% http://www.iis.ee.ethz.ch/~sha3
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Matlab Golden Model of Shabal
function [state_final, hashval] = Hash(hashbitlen, data, databitlen)
global sM nR
% constants
sM = 16; % block size
nR = 12; % parameter r
state_init = Init(hashbitlen);
state_update = Update(state_init, data, databitlen);
[state_final, hashval] = Final(state_update, data, databitlen, hashbitlen);
end
function state = Init(hashbitlen)
global sM nR
% Initialize the state (all zero, except the counter which is
% set to -1).
state.A = fi(zeros(1,nR),0,32,0);
state.B = fi(zeros(1,sM),0,32,0);
state.C = fi(zeros(1,sM),0,32,0);
state.Wlow = fi(hex2dec('FFFFFFFF'),0,32,0);
state.Whigh = fi(hex2dec('FFFFFFFF'),0,32,0);
% We compute the first two blocks, corresponding to the prefix,
% and process them immediately.
m = fi(zeros(1, sM),0,32,0);
for j = 1:sM:(2 * sM) % j={1,17}
for i = 1:sM
m(i) = hashbitlen + j + i - 2; % m(1)=hashbitlen (for 1st block)
end
% process block
state = input_block_add(state, m);
state = xor_counter(state);
state = apply_perm(state, m);
state = input_block_sub(state, m);
state = swap_bc(state);
state = incr_counter(state);
end
end
function state = Update(state, data, databitlen)
% Process all message blocks except the last one, which will be processed in
% Final().
messageblocks = databitlen/512;
for i=1:(messageblocks - 1)
m = data(((i-1)*16+1):(i*16));
% process block
state = input_block_add(state, m);
state = xor_counter(state);
state = apply_perm(state, m);
state = input_block_sub(state, m);
state = swap_bc(state);
state = incr_counter(state);
end
end
function [state, hashval] = Final(state, data, databitlen, hashbitlen)
global sM
nE = 3; % parameter e
% Now, we process the last (padded) block. We add three extra
% permutations, and we optimize away the unnecessary message
% additions and subtractions. There is no increment of the
% counter either in those last rounds (we keep the counter
% value used for the last data block). We transfer the swap to
% the next round, because there needs to be no final swap.
%
% Note that we reuse the final block in several calls
% to apply_perm().
messageblocks = databitlen/512;
m = data(((messageblocks-1)*16+1):(messageblocks*16));
state = input_block_add(state, m);
state = xor_counter(state);
state = apply_perm(state, m);
for i = 1:nE
state = swap_bc(state);
state = xor_counter(state);
state = apply_perm(state, m);
end
% The output consists of the B words, truncated to the requested
% length (in the formal description, the C words are used, but
% we omitted the last swap, so we have the words in B).
hashval = state.B(sM - hashbitlen/32 +1:sM);
end
% Swap the B and C state words.
function state = swap_bc(state)
t = state.B;
state.B = state.C;
state.C = t;
end
% Add the message block m to the B state words.
function state = input_block_add(state, m)
global sM
for i = 1:sM
state.B(i) = bitsliceget(state.B(i) + m(i),32);
end
end
% Subtract the message block m from the C state words.
function state = input_block_sub(state, m)
global sM
for i = 1:sM
state.C(i) = bitsliceget(fi(4294967296,0,33,0) + state.C(i) - m(i),32);
end
end
% Combine the block counter with the A state words.
function state = xor_counter(state)
state.A(1) = bitxor(state.A(1),state.Wlow);
state.A(2) = bitxor(state.A(2),state.Whigh);
end
% Increment the block counter, for the next block.
function state = incr_counter(state)
% The counter extends over two 32-bit words. We manually propagate
% the carry when needed.
state.Wlow = bitsliceget(state.Wlow+fi(1,0,32,0),32);
if state.Wlow == 0
state.Whigh = bitsliceget(state.Whigh+fi(1,0,32,0),32);
end
end
% Apply the core Shabal permutation. The message block is provided
% in the m parameter.
function state = apply_perm(state, m)
global sM nR
% offset values in keyed permutation
o1 = 13;
o2 = 9;
o3 = 6;
nP = 3; % parameter p
for i = 1:sM
state.B(i) = bitrol(state.B(i),17);
end
for j = 0:(nP - 1) % j=0:2
for i = 0:(sM - 1)
state.A(mod((i + sM * j), nR)+1) = bitxor(bitxor(bitxor(U(bitxor(bitxor(state.A(mod((i + sM * j), nR)+1),...
V(bitsliceget(...
bitrol(state.A(mod((i + sM * j + (nR - 1)), nR)+1),15),32))), state.C(mod((8 + sM - i), sM)+1))),...
state.B(mod((i + o1), sM)+1)),...
bitand(state.B(mod((i + o2), sM)+1), bitcmp(state.B(mod((i + o3), sM)+1)))),m(i+1));
state.B(i+1) = bitxor(bitrol(state.B(i+1), 1), bitcmp(state.A(mod((i + sM * j), nR)+1)));
end
end
for j = 0:((3*nR)-1) % j=0:35
state.A(mod((3*nR - 1 - j), nR)+1) = bitsliceget(state.A(mod((3*nR - 1 - j), nR)+1) + state.C(mod((3*nR*sM + 6 - j), sM)+1),32);
end
end
function y = U(x)
y = bitsliceget(fi(3,0,32,0) * x,32);
end
function y = V(x)
y = bitsliceget(fi(5,0,32,0) * x, 32);
end