- 49E31942E59726FDE97368B5651502C78EFA7602B31E77BDCE9AE745FAB817CBCACF9C166022805BB20BA25AD693CFCF5CF9841252044F5BEA30C89792E1A1E5
+ 87241E219925CCE47CD73892DC728607F14BD01324BA0B08D04DB6F2D7F2469958D4C65A5F3C26F2DB1857841857DCD3204FDC78238CAE3126905BB5A3CECC99
eucrypt/smg_keccak/smg_keccak.adb
(2 . 6)(2 . 166)
5
6 package body SMG_Keccak is
7
8 -- public function, sponge
9 procedure Sponge( Input : in Bitstream;
10 Block_Len : in Keccak_Rate;
11 Output : out Bitstream) is
12 Internal : State := (others => (others => 0));
13 begin
14 --absorb input into sponge in a loop on available blocks, including padding
15 declare
16 -- number of input blocks after padding (between 2 and block_len bits pad)
17 Padded_Blocks : constant Positive := 1 + (Input'Length + 1) / Block_Len;
18 Padded : Bitstream ( 1 .. Padded_Blocks * Block_Len );
19 Block : Bitstream ( 1 .. Block_Len );
20 begin
21 -- initialise Padded with 0 everywhere
22 Padded := ( others => 0 );
23 -- copy and pad input with rule 10*1
24 Padded( Padded'First .. Padded'First + Input'Length - 1 ) := Input;
25 Padded( Padded'First + Input'Length ) := 1;
26 Padded( Padded'Last ) := 1;
27
28 -- loop through padded input and absorb block by block into sponge
29 -- padded input IS a multiple of blocks, so no stray bits left
30 for B in 0 .. Padded_Blocks - 1 loop
31 -- first get the current block to absorb
32 Block := Padded( Padded'First + B * Block_Len ..
33 Padded'First + (B+1) * Block_Len - 1 );
34 AbsorbBlock( Block, Internal );
35 -- scramble state with Keccak function
36 Internal := Keccak_Function( Internal );
37
38 end loop; -- end absorb loop for blocks
39 end; -- end absorb stage
40
41 --squeeze required bits from sponge in a loop as needed
42 declare
43 -- full blocks per output
44 BPO : constant Natural := Output'Length / Block_Len;
45 -- stray bits per output
46 SPO : constant Natural := Output'Length mod Block_Len;
47 Block : Bitstream( 1 .. Block_Len );
48 begin
49 -- squeeze block by block (if at least one full block is needed)
50 for I in 0 .. BPO - 1 loop
51 SqueezeBlock( Block, Internal );
52 Output( Output'First + I * Block_Len ..
53 Output'First + (I + 1) * Block_Len -1) := Block;
54
55 -- scramble state
56 Internal := Keccak_Function( Internal );
57 end loop; -- end squeezing full blocks
58
59 -- squeeze any partial block needed (stray bits)
60 if SPO > 0 then
61 SqueezeBlock( Block, Internal );
62 Output( Output'Last - SPO + 1 .. Output'Last ) :=
63 Block( Block'First .. Block'First + SPO - 1 );
64 end if; -- end squeezing partial last block (stray bits)
65
66 end; -- end squeeze stage
67 end Sponge;
68
69 -- convert from a bitstream of ZWord size to an actual ZWord number
70 -- first bit of bitstream will be most significant bit of ZWord
71 function BitsToWord( Bits: in Bitword ) return ZWord is
72 W: ZWord;
73 P: Natural;
74 begin
75 W := 0;
76 P := 0;
77 for I in reverse Bitword'Range loop
78 W := W + ZWord( Bits(I) ) * ( 2**P );
79 P := P + 1;
80 end loop;
81 return W;
82 end BitsToWord;
83
84 -- convert from a ZWord (lane of state) to a bitstream of ZWord size
85 -- most significant bit of ZWord will be left most bit of bitstream
86 function WordToBits( Word: in ZWord ) return Bitword is
87 Bits: Bitword := (others => 0);
88 W: ZWord;
89 begin
90 W := Word;
91 for I in reverse Bitword'Range loop
92 Bits( I ) := Bit( W mod 2 );
93 W := W / 2;
94 end loop;
95 return Bits;
96 end WordToBits;
97
98 -- helper procedures for sponge absorb/squeeze
99
100 -- NO scramble here, this will absorb ALL given block, make sure it fits!
101 procedure AbsorbBlock( Block: in Bitstream; S: in out State ) is
102 WPB: constant Natural := Block'Length / Z_Length; -- words per block
103 SBB: constant Natural := Block'Length mod Z_Length; -- stray bits
104 FromPos, ToPos : Natural;
105 X, Y : XYCoord;
106 Word : ZWord;
107 BWord : Bitword;
108 begin
109 -- xor current block into first Block'Length bits of state
110 -- a block can consist in more than one word
111 X := 0;
112 Y := 0;
113 for I in 0..WPB-1 loop
114 FromPos := Block'First + I * Z_Length;
115 ToPos := FromPos + Z_Length - 1;
116 Word := BitsToWord( Block( FromPos .. ToPos ) );
117 S( X, Y ) := S( X, Y ) xor Word;
118 -- move on to next word in state
119 X := X + 1;
120 if X = 0 then
121 Y := Y + 1;
122 end if;
123 end loop;
124 -- absorb also any remaining bits from block
125 if SBB > 0 then
126 ToPos := Block'Last;
127 FromPos := ToPos - SBB + 1;
128 BWord := (others => 0);
129 BWord(Bitword'First .. Bitword'First + SBB - 1) := Block(ToPos..FromPos);
130 Word := BitsToWord( BWord );
131 S( X, Y ) := S( X, Y ) xor Word;
132 end if;
133 end AbsorbBlock;
134
135 -- NO scramble here, this will squeeze Block'Length bits out of *same* state S
136 procedure SqueezeBlock( Block: out Bitstream; S: in State) is
137 X, Y : XYCoord;
138 BWord : Bitword;
139 FromPos : Natural;
140 Len : Natural;
141 begin
142 X := 0;
143 Y := 0;
144 FromPos := Block'First;
145
146 while FromPos <= Block'Last loop
147 BWord := WordToBits( S(X, Y) );
148
149 X := X + 1;
150 if X = 0 then
151 Y := Y + 1;
152 end if;
153
154 -- copy full word if it fits or
155 -- only as many bits as are still needed to fill the block
156 Len := Block'Last - FromPos + 1;
157 if Len > Z_Length then
158 Len := Z_Length;
159 end if;
160
161 Block(FromPos..FromPos+Len-1) := BWord(BWord'First..BWord'First+Len-1);
162 FromPos := FromPos + Len;
163 end loop;
164 end SqueezeBlock;
165
166
167 -- private, internal transformations
168 function Theta(Input : in State) return State is
169 Output : State;
170 C : Plane;