-- S.MG implementation of Keccak-f permutations -- (Based on The Keccak Reference, Version 3.0, January 14, 2011, by -- Guido Bertoni, Joan Daemen, Michael Peeters and Gilles Van Assche) -- NB: this is a byte-level (octet) implementation! -- Input/output are always multiple of octets, NOT bits. -- S.MG, 2018 with Ada.Unchecked_Conversion; --for byteword to zword with Interfaces.C; with Interfaces; package SMG_Keccak is pragma Pure(SMG_Keccak); --stateless, no side effects -> can cache calls --knobs (can change as per keccak design but fixed here for S.MG purposes)-- Keccak_L: constant := 6; --gives keccak z (word) dimension of 2^6=64 and --therefore keccak function 1600 with current --constants (5*5*2^6) Default_Byterate: constant := 168;--max octets the sponge can eat/spit without --needing to scramble the state --constants: dimensions of keccak state and number of rounds XY_Length: constant := 5; Z_Length: constant := 2**Keccak_L; Width: constant := XY_Length * XY_Length * Z_Length; N_Rounds: constant := 12 + 2*Keccak_L; --types type XYCoord is mod XY_Length; type ZCoord is mod Z_Length; type Round_Index is mod N_Rounds; type ZWord is mod 2**Z_Length; --"lane" in keccak ref type Plane is array(XYCoord) of ZWord; --a "horizontal slice" of keccak state type State is array(XYCoord, XYCoord) of ZWord; --the full keccak state type Round_Constants is array(Round_Index) of ZWord; --magic keccak constants -- rate can be chosen by caller at each call, between 1 and width of state /8 -- higher rate means sponge "eats" more octets at a time but has fewer octets -- in the "secret" part of the state (i.e. lower capacity) subtype Keccak_Rate is Positive range 1..Width/8; -- capacity = width - rate type Bytestream is array( Natural range <> ) of Interfaces.Unsigned_8; subtype Byteword is Bytestream( 0..Z_Length/8-1); --octets of one state "word" function Cast is new Ada.Unchecked_Conversion (Byteword, ZWord); function Cast is new Ada.Unchecked_Conversion (ZWord, Byteword); -- type conversions -- NB: those are NOT perfect opposites! -- BytesToWord assumes input is raw and in LSB order, will flip on MSB iron -- WordToBytes assumes input is MSB and will flip on LSB -- This is because the Sponge squeezes MSB but absorbs LSB... function BytesToWordLE( BWord : in Byteword ) return ZWord; function WordToBytesBE( Word : in ZWord ) return Byteword; -- flip input octets (i.e. groups of 8 bits) function FlipOctets( BWord : in Byteword ) return Byteword; -- public function, the sponge itself -- Keccak sponge structure using Keccak_Function, Pad and a given octetrate; -- Input - the stream of bits to hash (the message) -- Output - a bytestream of desired size for holding output -- Block_Len - the octetrate to use; this is effectively the block length -- for splitting Input AND squeezing output between scrambles procedure Sponge(Input : in Bytestream; Output : out Bytestream; Block_Len : in Keccak_Rate := Default_Byterate ); Reverse_Table : constant array(0..255) of Interfaces.Unsigned_8 := ( 16#00#, 16#80#, 16#40#, 16#C0#, 16#20#, 16#A0#, 16#60#, 16#E0#, 16#10#, 16#90#, 16#50#, 16#D0#, 16#30#, 16#B0#, 16#70#, 16#F0#, 16#08#, 16#88#, 16#48#, 16#C8#, 16#28#, 16#A8#, 16#68#, 16#E8#, 16#18#, 16#98#, 16#58#, 16#D8#, 16#38#, 16#B8#, 16#78#, 16#F8#, 16#04#, 16#84#, 16#44#, 16#C4#, 16#24#, 16#A4#, 16#64#, 16#E4#, 16#14#, 16#94#, 16#54#, 16#D4#, 16#34#, 16#B4#, 16#74#, 16#F4#, 16#0C#, 16#8C#, 16#4C#, 16#CC#, 16#2C#, 16#AC#, 16#6C#, 16#EC#, 16#1C#, 16#9C#, 16#5C#, 16#DC#, 16#3C#, 16#BC#, 16#7C#, 16#FC#, 16#02#, 16#82#, 16#42#, 16#C2#, 16#22#, 16#A2#, 16#62#, 16#E2#, 16#12#, 16#92#, 16#52#, 16#D2#, 16#32#, 16#B2#, 16#72#, 16#F2#, 16#0A#, 16#8A#, 16#4A#, 16#CA#, 16#2A#, 16#AA#, 16#6A#, 16#EA#, 16#1A#, 16#9A#, 16#5A#, 16#DA#, 16#3A#, 16#BA#, 16#7A#, 16#FA#, 16#06#, 16#86#, 16#46#, 16#C6#, 16#26#, 16#A6#, 16#66#, 16#E6#, 16#16#, 16#96#, 16#56#, 16#D6#, 16#36#, 16#B6#, 16#76#, 16#F6#, 16#0E#, 16#8E#, 16#4E#, 16#CE#, 16#2E#, 16#AE#, 16#6E#, 16#EE#, 16#1E#, 16#9E#, 16#5E#, 16#DE#, 16#3E#, 16#BE#, 16#7E#, 16#FE#, 16#01#, 16#81#, 16#41#, 16#C1#, 16#21#, 16#A1#, 16#61#, 16#E1#, 16#11#, 16#91#, 16#51#, 16#D1#, 16#31#, 16#B1#, 16#71#, 16#F1#, 16#09#, 16#89#, 16#49#, 16#C9#, 16#29#, 16#A9#, 16#69#, 16#E9#, 16#19#, 16#99#, 16#59#, 16#D9#, 16#39#, 16#B9#, 16#79#, 16#F9#, 16#05#, 16#85#, 16#45#, 16#C5#, 16#25#, 16#A5#, 16#65#, 16#E5#, 16#15#, 16#95#, 16#55#, 16#D5#, 16#35#, 16#B5#, 16#75#, 16#F5#, 16#0D#, 16#8D#, 16#4D#, 16#CD#, 16#2D#, 16#AD#, 16#6D#, 16#ED#, 16#1D#, 16#9D#, 16#5D#, 16#DD#, 16#3D#, 16#BD#, 16#7D#, 16#FD#, 16#03#, 16#83#, 16#43#, 16#C3#, 16#23#, 16#A3#, 16#63#, 16#E3#, 16#13#, 16#93#, 16#53#, 16#D3#, 16#33#, 16#B3#, 16#73#, 16#F3#, 16#0B#, 16#8B#, 16#4B#, 16#CB#, 16#2B#, 16#AB#, 16#6B#, 16#EB#, 16#1B#, 16#9B#, 16#5B#, 16#DB#, 16#3B#, 16#BB#, 16#7B#, 16#FB#, 16#07#, 16#87#, 16#47#, 16#C7#, 16#27#, 16#A7#, 16#67#, 16#E7#, 16#17#, 16#97#, 16#57#, 16#D7#, 16#37#, 16#B7#, 16#77#, 16#F7#, 16#0F#, 16#8F#, 16#4F#, 16#CF#, 16#2F#, 16#AF#, 16#6F#, 16#EF#, 16#1F#, 16#9F#, 16#5F#, 16#DF#, 16#3F#, 16#BF#, 16#7F#, 16#FF#); private -- these are internals of the keccak implementation, not meant to be directly -- accessed/used -- this will squeeze Block'Length octets out of state S -- NO scramble of state in here! -- NB: make SURE that Block'Length is the correct octetrate for this sponge -- esp: Block'Length should be a correct octetrate aka LESS than Width/8 procedure SqueezeBlock( Block: out Bytestream; S: in State); -- This absorbs into sponge the given block, modifying the state accordingly -- NO scramble of state in here so make sure the whole Block fits in state! -- NB: make SURE that Block'Length is *the correct byterate* for this sponge -- esp: Block'Length should be a correct byterate aka LESS than Width procedure AbsorbBlock( Block: in Bytestream; S: in out State ); --Keccak magic numbers RC : constant Round_Constants := ( 16#0000_0000_0000_0001#, 16#0000_0000_0000_8082#, 16#8000_0000_0000_808A#, 16#8000_0000_8000_8000#, 16#0000_0000_0000_808B#, 16#0000_0000_8000_0001#, 16#8000_0000_8000_8081#, 16#8000_0000_0000_8009#, 16#0000_0000_0000_008A#, 16#0000_0000_0000_0088#, 16#0000_0000_8000_8009#, 16#0000_0000_8000_000A#, 16#0000_0000_8000_808B#, 16#8000_0000_0000_008B#, 16#8000_0000_0000_8089#, 16#8000_0000_0000_8003#, 16#8000_0000_0000_8002#, 16#8000_0000_0000_0080#, 16#0000_0000_0000_800A#, 16#8000_0000_8000_000A#, 16#8000_0000_8000_8081#, 16#8000_0000_0000_8080#, 16#0000_0000_8000_0001#, 16#8000_0000_8000_8008# ); --gnat-specific methods to have bit-ops for modular types function Rotate_Left( Value : ZWord; Amount : Natural) return ZWord; pragma Import(Intrinsic, Rotate_Left); function Shift_Right( Value : ZWord; Amount : Natural) return ZWord; pragma Import(Intrinsic, Shift_Right); function Shift_Left( Value : ZWord; Amount : Natural) return ZWord; pragma Import(Intrinsic, Shift_Left); --Keccak transformations of the internal state function Theta ( Input : in State) return State; function Rho ( Input : in State) return State; function Pi ( Input : in State) return State; function Chi ( Input : in State) return State; function Iota ( Round_Const : in ZWord; Input : in State) return State; --Keccak function with block width currently 1600 (Width constant above) --this simply applies *all* keccak transformations in the correct order, using -- the keccak magic numbers (round constants) as per keccak reference function Keccak_Function(Input: in State) return State; end SMG_Keccak;