raw
eucrypt_ch6_kecca...    1  -- S.MG, 2018
eucrypt_ch6_kecca... 2
eucrypt_ch6_kecca... 3 package body SMG_Keccak is
eucrypt_ch6_kecca... 4
eucrypt_ch7_kecca... 5 -- public function, sponge
eucrypt_ch7_kecca... 6 procedure Sponge( Input : in Bitstream;
eucrypt_ch7_kecca... 7 Block_Len : in Keccak_Rate;
eucrypt_ch7_kecca... 8 Output : out Bitstream) is
eucrypt_ch7_kecca... 9 Internal : State := (others => (others => 0));
eucrypt_ch7_kecca... 10 begin
eucrypt_ch7_kecca... 11 --absorb input into sponge in a loop on available blocks, including padding
eucrypt_ch7_kecca... 12 declare
eucrypt_ch7_kecca... 13 -- number of input blocks after padding (between 2 and block_len bits pad)
eucrypt_ch7_kecca... 14 Padded_Blocks : constant Positive := 1 + (Input'Length + 1) / Block_Len;
eucrypt_ch7_kecca... 15 Padded : Bitstream ( 1 .. Padded_Blocks * Block_Len );
eucrypt_ch7_kecca... 16 Block : Bitstream ( 1 .. Block_Len );
eucrypt_ch7_kecca... 17 begin
eucrypt_ch7_kecca... 18 -- initialise Padded with 0 everywhere
eucrypt_ch7_kecca... 19 Padded := ( others => 0 );
eucrypt_ch7_kecca... 20 -- copy and pad input with rule 10*1
eucrypt_ch7_kecca... 21 Padded( Padded'First .. Padded'First + Input'Length - 1 ) := Input;
eucrypt_ch7_kecca... 22 Padded( Padded'First + Input'Length ) := 1;
eucrypt_ch7_kecca... 23 Padded( Padded'Last ) := 1;
eucrypt_ch7_kecca... 24
eucrypt_ch7_kecca... 25 -- loop through padded input and absorb block by block into sponge
eucrypt_ch7_kecca... 26 -- padded input IS a multiple of blocks, so no stray bits left
eucrypt_ch7_kecca... 27 for B in 0 .. Padded_Blocks - 1 loop
eucrypt_ch7_kecca... 28 -- first get the current block to absorb
eucrypt_ch7_kecca... 29 Block := Padded( Padded'First + B * Block_Len ..
eucrypt_ch7_kecca... 30 Padded'First + (B+1) * Block_Len - 1 );
eucrypt_ch7_kecca... 31 AbsorbBlock( Block, Internal );
eucrypt_ch7_kecca... 32 -- scramble state with Keccak function
eucrypt_ch7_kecca... 33 Internal := Keccak_Function( Internal );
eucrypt_ch7_kecca... 34
eucrypt_ch7_kecca... 35 end loop; -- end absorb loop for blocks
eucrypt_ch7_kecca... 36 end; -- end absorb stage
eucrypt_ch7_kecca... 37
eucrypt_ch7_kecca... 38 --squeeze required bits from sponge in a loop as needed
eucrypt_ch7_kecca... 39 declare
eucrypt_ch7_kecca... 40 -- full blocks per output
eucrypt_ch7_kecca... 41 BPO : constant Natural := Output'Length / Block_Len;
eucrypt_ch7_kecca... 42 -- stray bits per output
eucrypt_ch7_kecca... 43 SPO : constant Natural := Output'Length mod Block_Len;
eucrypt_ch7_kecca... 44 Block : Bitstream( 1 .. Block_Len );
eucrypt_ch7_kecca... 45 begin
eucrypt_ch7_kecca... 46 -- squeeze block by block (if at least one full block is needed)
eucrypt_ch7_kecca... 47 for I in 0 .. BPO - 1 loop
eucrypt_ch7_kecca... 48 SqueezeBlock( Block, Internal );
eucrypt_ch7_kecca... 49 Output( Output'First + I * Block_Len ..
eucrypt_ch7_kecca... 50 Output'First + (I + 1) * Block_Len -1) := Block;
eucrypt_ch7_kecca... 51
eucrypt_ch7_kecca... 52 -- scramble state
eucrypt_ch7_kecca... 53 Internal := Keccak_Function( Internal );
eucrypt_ch7_kecca... 54 end loop; -- end squeezing full blocks
eucrypt_ch7_kecca... 55
eucrypt_ch7_kecca... 56 -- squeeze any partial block needed (stray bits)
eucrypt_ch7_kecca... 57 if SPO > 0 then
eucrypt_ch7_kecca... 58 SqueezeBlock( Block, Internal );
eucrypt_ch7_kecca... 59 Output( Output'Last - SPO + 1 .. Output'Last ) :=
eucrypt_ch7_kecca... 60 Block( Block'First .. Block'First + SPO - 1 );
eucrypt_ch7_kecca... 61 end if; -- end squeezing partial last block (stray bits)
eucrypt_ch7_kecca... 62
eucrypt_ch7_kecca... 63 end; -- end squeeze stage
eucrypt_ch7_kecca... 64 end Sponge;
eucrypt_ch7_kecca... 65
eucrypt_ch7_kecca... 66 -- convert from a bitstream of ZWord size to an actual ZWord number
eucrypt_ch7_kecca... 67 -- first bit of bitstream will be most significant bit of ZWord
eucrypt_ch7_kecca... 68 function BitsToWord( Bits: in Bitword ) return ZWord is
eucrypt_ch7_kecca... 69 W: ZWord;
eucrypt_ch7_kecca... 70 P: Natural;
eucrypt_ch7_kecca... 71 begin
eucrypt_ch7_kecca... 72 W := 0;
eucrypt_ch7_kecca... 73 P := 0;
eucrypt_ch7_kecca... 74 for I in reverse Bitword'Range loop
eucrypt_ch7_kecca... 75 W := W + ZWord( Bits(I) ) * ( 2**P );
eucrypt_ch7_kecca... 76 P := P + 1;
eucrypt_ch7_kecca... 77 end loop;
eucrypt_ch7_kecca... 78 return W;
eucrypt_ch7_kecca... 79 end BitsToWord;
eucrypt_ch7_kecca... 80
eucrypt_ch7_kecca... 81 -- convert from a ZWord (lane of state) to a bitstream of ZWord size
eucrypt_ch7_kecca... 82 -- most significant bit of ZWord will be left most bit of bitstream
eucrypt_ch7_kecca... 83 function WordToBits( Word: in ZWord ) return Bitword is
eucrypt_ch7_kecca... 84 Bits: Bitword := (others => 0);
eucrypt_ch7_kecca... 85 W: ZWord;
eucrypt_ch7_kecca... 86 begin
eucrypt_ch7_kecca... 87 W := Word;
eucrypt_ch7_kecca... 88 for I in reverse Bitword'Range loop
eucrypt_ch7_kecca... 89 Bits( I ) := Bit( W mod 2 );
eucrypt_ch7_kecca... 90 W := W / 2;
eucrypt_ch7_kecca... 91 end loop;
eucrypt_ch7_kecca... 92 return Bits;
eucrypt_ch7_kecca... 93 end WordToBits;
eucrypt_ch7_kecca... 94
eucrypt_ch7_kecca... 95 -- helper procedures for sponge absorb/squeeze
eucrypt_ch7_kecca... 96
eucrypt_ch7_kecca... 97 -- NO scramble here, this will absorb ALL given block, make sure it fits!
eucrypt_ch7_kecca... 98 procedure AbsorbBlock( Block: in Bitstream; S: in out State ) is
eucrypt_ch7_kecca... 99 WPB: constant Natural := Block'Length / Z_Length; -- words per block
eucrypt_ch7_kecca... 100 SBB: constant Natural := Block'Length mod Z_Length; -- stray bits
eucrypt_ch7_kecca... 101 FromPos, ToPos : Natural;
eucrypt_ch7_kecca... 102 X, Y : XYCoord;
eucrypt_ch7_kecca... 103 Word : ZWord;
eucrypt_ch7_kecca... 104 BWord : Bitword;
eucrypt_ch7_kecca... 105 begin
eucrypt_ch7_kecca... 106 -- xor current block into first Block'Length bits of state
eucrypt_ch7_kecca... 107 -- a block can consist in more than one word
eucrypt_ch7_kecca... 108 X := 0;
eucrypt_ch7_kecca... 109 Y := 0;
eucrypt_ch7_kecca... 110 for I in 0..WPB-1 loop
eucrypt_ch7_kecca... 111 FromPos := Block'First + I * Z_Length;
eucrypt_ch7_kecca... 112 ToPos := FromPos + Z_Length - 1;
eucrypt_ch7_kecca... 113 Word := BitsToWord( Block( FromPos .. ToPos ) );
eucrypt_ch7_kecca... 114 S( X, Y ) := S( X, Y ) xor Word;
eucrypt_ch7_kecca... 115 -- move on to next word in state
eucrypt_ch7_kecca... 116 X := X + 1;
eucrypt_ch7_kecca... 117 if X = 0 then
eucrypt_ch7_kecca... 118 Y := Y + 1;
eucrypt_ch7_kecca... 119 end if;
eucrypt_ch7_kecca... 120 end loop;
eucrypt_ch7_kecca... 121 -- absorb also any remaining bits from block
eucrypt_ch7_kecca... 122 if SBB > 0 then
eucrypt_ch7_kecca... 123 ToPos := Block'Last;
eucrypt_ch7_kecca... 124 FromPos := ToPos - SBB + 1;
eucrypt_ch7_kecca... 125 BWord := (others => 0);
eucrypt_ch7_kecca... 126 BWord(Bitword'First .. Bitword'First + SBB - 1) := Block(ToPos..FromPos);
eucrypt_ch7_kecca... 127 Word := BitsToWord( BWord );
eucrypt_ch7_kecca... 128 S( X, Y ) := S( X, Y ) xor Word;
eucrypt_ch7_kecca... 129 end if;
eucrypt_ch7_kecca... 130 end AbsorbBlock;
eucrypt_ch7_kecca... 131
eucrypt_ch7_kecca... 132 -- NO scramble here, this will squeeze Block'Length bits out of *same* state S
eucrypt_ch7_kecca... 133 procedure SqueezeBlock( Block: out Bitstream; S: in State) is
eucrypt_ch7_kecca... 134 X, Y : XYCoord;
eucrypt_ch7_kecca... 135 BWord : Bitword;
eucrypt_ch7_kecca... 136 FromPos : Natural;
eucrypt_ch7_kecca... 137 Len : Natural;
eucrypt_ch7_kecca... 138 begin
eucrypt_ch7_kecca... 139 X := 0;
eucrypt_ch7_kecca... 140 Y := 0;
eucrypt_ch7_kecca... 141 FromPos := Block'First;
eucrypt_ch7_kecca... 142
eucrypt_ch7_kecca... 143 while FromPos <= Block'Last loop
eucrypt_ch7_kecca... 144 BWord := WordToBits( S(X, Y) );
eucrypt_ch7_kecca... 145
eucrypt_ch7_kecca... 146 X := X + 1;
eucrypt_ch7_kecca... 147 if X = 0 then
eucrypt_ch7_kecca... 148 Y := Y + 1;
eucrypt_ch7_kecca... 149 end if;
eucrypt_ch7_kecca... 150
eucrypt_ch7_kecca... 151 -- copy full word if it fits or
eucrypt_ch7_kecca... 152 -- only as many bits as are still needed to fill the block
eucrypt_ch7_kecca... 153 Len := Block'Last - FromPos + 1;
eucrypt_ch7_kecca... 154 if Len > Z_Length then
eucrypt_ch7_kecca... 155 Len := Z_Length;
eucrypt_ch7_kecca... 156 end if;
eucrypt_ch7_kecca... 157
eucrypt_ch7_kecca... 158 Block(FromPos..FromPos+Len-1) := BWord(BWord'First..BWord'First+Len-1);
eucrypt_ch7_kecca... 159 FromPos := FromPos + Len;
eucrypt_ch7_kecca... 160 end loop;
eucrypt_ch7_kecca... 161 end SqueezeBlock;
eucrypt_ch7_kecca... 162
eucrypt_ch7_kecca... 163
eucrypt_ch7_kecca... 164 -- private, internal transformations
eucrypt_ch6_kecca... 165 function Theta(Input : in State) return State is
eucrypt_ch6_kecca... 166 Output : State;
eucrypt_ch6_kecca... 167 C : Plane;
eucrypt_ch6_kecca... 168 W : ZWord;
eucrypt_ch6_kecca... 169 begin
eucrypt_ch6_kecca... 170 for X in XYCoord loop
eucrypt_ch6_kecca... 171 C(X) := Input(X, 0);
eucrypt_ch6_kecca... 172 for Y in 1..XYCoord'Last loop
eucrypt_ch6_kecca... 173 C(X) := C(X) xor Input(X, Y);
eucrypt_ch6_kecca... 174 end loop;
eucrypt_ch6_kecca... 175 end loop;
eucrypt_ch6_kecca... 176
eucrypt_ch6_kecca... 177 for X in XYCoord loop
eucrypt_ch6_kecca... 178 W := C(X-1) xor Rotate_Left(C(X+1), 1);
eucrypt_ch6_kecca... 179 for Y in XYCoord loop
eucrypt_ch6_kecca... 180 Output(X,Y) := Input(X,Y) xor W;
eucrypt_ch6_kecca... 181 end loop;
eucrypt_ch6_kecca... 182 end loop;
eucrypt_ch6_kecca... 183
eucrypt_ch6_kecca... 184 return Output;
eucrypt_ch6_kecca... 185 end Theta;
eucrypt_ch6_kecca... 186
eucrypt_ch6_kecca... 187 function Rho(Input : in State) return State is
eucrypt_ch6_kecca... 188 Output : State;
eucrypt_ch6_kecca... 189 X, Y, Old_Y : XYCoord;
eucrypt_ch6_kecca... 190 begin
eucrypt_ch6_kecca... 191 Output(0,0) := Input(0,0);
eucrypt_ch6_kecca... 192 X := 1;
eucrypt_ch6_kecca... 193 Y := 0;
eucrypt_ch6_kecca... 194
eucrypt_ch6_kecca... 195 for T in 0..23 loop
eucrypt_ch6_kecca... 196 Output(X, Y) := Rotate_Left(Input(X,Y), ((T+1)*(T+2)/2) mod Z_Length);
eucrypt_ch6_kecca... 197 Old_Y := Y;
eucrypt_ch6_kecca... 198 Y := 2*X + 3*Y;
eucrypt_ch6_kecca... 199 X := Old_Y;
eucrypt_ch6_kecca... 200 end loop;
eucrypt_ch6_kecca... 201 return Output;
eucrypt_ch6_kecca... 202 end rho;
eucrypt_ch6_kecca... 203
eucrypt_ch6_kecca... 204 function Pi(Input : in State) return State is
eucrypt_ch6_kecca... 205 Output: State;
eucrypt_ch6_kecca... 206 begin
eucrypt_ch6_kecca... 207 for X in XYCoord loop
eucrypt_ch6_kecca... 208 for Y in XYCoord loop
eucrypt_ch6_kecca... 209 Output(Y, 2*X + 3*Y) := Input(X, Y);
eucrypt_ch6_kecca... 210 end loop;
eucrypt_ch6_kecca... 211 end loop;
eucrypt_ch6_kecca... 212 return Output;
eucrypt_ch6_kecca... 213 end pi;
eucrypt_ch6_kecca... 214
eucrypt_ch6_kecca... 215 function Chi(Input : in State) return State is
eucrypt_ch6_kecca... 216 Output: State;
eucrypt_ch6_kecca... 217 begin
eucrypt_ch6_kecca... 218 for Y in XYCoord loop
eucrypt_ch6_kecca... 219 for X in XYCoord loop
eucrypt_ch6_kecca... 220 Output(X, Y) := Input(X, Y) xor
eucrypt_ch6_kecca... 221 ( (not Input(X + 1, Y)) and Input(X + 2, Y) );
eucrypt_ch6_kecca... 222 end loop;
eucrypt_ch6_kecca... 223 end loop;
eucrypt_ch6_kecca... 224 return Output;
eucrypt_ch6_kecca... 225 end chi;
eucrypt_ch6_kecca... 226
eucrypt_ch6_kecca... 227 function Iota(Round_Const : in ZWord; Input : in State) return State is
eucrypt_ch6_kecca... 228 Output: State;
eucrypt_ch6_kecca... 229 begin
eucrypt_ch6_kecca... 230 Output := Input;
eucrypt_ch6_kecca... 231 Output(0,0) := Input(0,0) xor Round_Const;
eucrypt_ch6_kecca... 232 return Output;
eucrypt_ch6_kecca... 233 end iota;
eucrypt_ch6_kecca... 234
eucrypt_ch6_kecca... 235 function Keccak_Function(Input: in State) return State is
eucrypt_ch6_kecca... 236 Output: State;
eucrypt_ch6_kecca... 237 begin
eucrypt_ch6_kecca... 238 Output := Input;
eucrypt_ch6_kecca... 239 for I in Round_Index loop
eucrypt_ch6_kecca... 240 Output := Iota(RC(I), Chi(Pi(Rho(Theta(Output)))));
eucrypt_ch6_kecca... 241 end loop;
eucrypt_ch6_kecca... 242
eucrypt_ch6_kecca... 243 return Output;
eucrypt_ch6_kecca... 244 end Keccak_Function;
eucrypt_ch6_kecca... 245
eucrypt_ch6_kecca... 246 end SMG_Keccak;