steelcrypt/src/algorithms/sha3/sha3_generic.adb

138 lines
4.6 KiB
Ada

-- Copyright (C) 2015 Daniel Otte <bg@nerilex.org>
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
package body Sha3_Generic is
procedure Initialize(Context : out Context_T) is
begin
Context.A := (others => (others => 0));
end Initialize;
procedure Next_Block(Context : in out Context_T; Block : in Block_T) is
temp : u64;
begin
for i in 0 .. Rate_Bytes / 8 - 1 loop
temp := Load_le(Block(Block'First + i * 8 .. Block'First + i * 8 + 7));
Context.A(x_T(i mod 5), y_T(i / 5)) := Context.A(x_T(i mod 5), y_T(i / 5)) xor temp;
end loop;
Permute(Context.A);
end Next_Block;
procedure Append_Bit(Context : in out Context_T; Index : in out Capacity_T; Value : in Bit) is
begin
Context.A(x_t((Index / w) mod 5), y_t(Index / w / 5)) := Context.A(x_t((Index / w) mod 5), y_t(Index / w / 5)) xor Shift_Left(Word_T(Value), Index mod w);
Index := Index + 1;
if Index = Rate_Bits then
Permute(Context.A);
Index := 0;
end if;
end Append_Bit;
procedure Append_Byte(Context : in out Context_T; Index : in out Capacity_T; Value : in u8) is
begin
if Index mod 8 /= 0 then
raise Constraint_Error;
end if;
Context.A(x_t((Index / w) mod 5), y_t(Index / w / 5)) := Context.A(x_t((Index / w) mod 5), y_t(Index / w / 5)) xor Shift_Left(Word_T(Value), Index mod w);
Index := Index + 8;
if Index = Rate_Bits then
Permute(Context.A);
Index := 0;
end if;
end Append_Byte;
procedure Last_Block(Context : in out Context_T; Block : in u8_Array; Bits : in Integer := -1) is
Length : Natural;
Index : Integer := Block'First;
Dest_Index : Natural := 0;
begin
if Bits < 0 then
Length := Block'Length * 8;
else
Length := Bits;
end if;
while Length >= Rate_Bits loop
Next_Block(Context, Block(Index .. Index + Rate_Bytes - 1));
Index := Index + Rate_Bytes;
Length := Length - Rate_bits;
end loop;
-- append trailing bytes
while Length >= 8 loop
Append_Byte(Context, Dest_Index, Block(Index));
Index := Index + 1;
Length := Length - 8;
end loop;
-- append trailing bits
for j in 0 .. Length - 1 loop
Append_Bit(Context, Dest_Index, Bit(Shift_Right(Block(Index), j) mod 2));
end loop;
-- append suffix
for j in 0 .. Suffix_Bit_Length - 1 loop
Append_Bit(Context, Dest_Index, Bit(Shift_Right(Suffix, Natural(j)) mod 2));
end loop;
-- insert Padding
Append_Bit(Context, Dest_Index, 1);
Dest_Index := Rate_Bits - 1;
Append_Bit(Context, Dest_Index, 1);
end Last_Block;
procedure Squeeze(Context : in out Context_T; Data : out u8_Array) is
Temp : u8_Array(1 .. 8);
Length_A : Integer := Data'First;
Length_B : Integer;
j : Natural;
begin
for i in 0 .. Data'Length / Rate_Bytes loop
Length_B := Length_A + Rate_Bytes - 1;
if Length_B > Data'Last then
Length_B := Data'Last;
end if;
j := 0;
while Length_A + 8 <= Length_B loop
Store_le(Data(Length_A .. Length_A + 7), Context.A(x_t(j mod 5), y_t(j / 5)));
Length_A := Length_A + 8;
j := j + 1;
end loop;
if Length_A <= Length_B then
Store_le(Temp, Context.A(x_t(j mod 5), y_t(j / 5)));
Data(Length_A .. Length_B) := Temp(Temp'First .. Temp'First + Length_B - Length_A);
end if;
Length_A := Length_B;
if Length_B < Data'Last then
Permute(Context.A);
end if;
end loop;
end Squeeze;
procedure Get_Digest(Context : in out Context_T; Digest : out Digest_T) is
begin
Squeeze(Context, Digest);
end Get_Digest;
procedure Hash(Data : in u8_Array; Digest : out Digest_T; Bits : in Integer := -1) is
Ctx : Context_T;
begin
Initialize(Ctx);
Last_Block(Ctx, Data, Bits);
Get_Digest(Ctx, Digest);
end Hash;
end Sha3_Generic;