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