CryptoKeccakF1600.Mod 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. MODULE CryptoKeccakF1600; (** AUTHOR "GF"; PURPOSE "KeccakF-1600 sponge function"; *)
  2. (*
  3. The Keccak sponge function, designed by Guido Bertoni, Joan Daemen,
  4. Michaël Peeters and Gilles Van Assche. For more information, feedback or
  5. questions, please refer to our website: http://keccak.noekeon.org/
  6. *)
  7. IMPORT S := SYSTEM;
  8. CONST
  9. Width* = 1600; (* state size in bits *)
  10. LaneSize* = 8; (* lane size in bytes *)
  11. CONST
  12. nrRounds = 24; nrLanes = 25;
  13. TYPE
  14. Lane = RECORD low, high: SET32 END;
  15. State = ARRAY nrLanes OF Lane;
  16. VAR
  17. roundConstants: ARRAY nrRounds OF Lane;
  18. rhoOffsets: ARRAY nrLanes OF LONGINT;
  19. TYPE
  20. Instance* = OBJECT
  21. VAR
  22. state: State;
  23. PROCEDURE & Init*;
  24. BEGIN
  25. Initialize
  26. END Init;
  27. PROCEDURE Initialize*;
  28. VAR i: LONGINT;
  29. BEGIN
  30. FOR i := 0 TO nrLanes-1 DO state[i].low := {}; state[i].high := {} END
  31. END Initialize;
  32. PROCEDURE XORBytesInLane*( laneNo, laneOffset, length: LONGINT; CONST data: ARRAY OF CHAR; dataOffset: LONGINT );
  33. VAR
  34. lane: Lane;
  35. BEGIN
  36. ASSERT( (laneNo < nrLanes) & (laneOffset < LaneSize) & (laneOffset+length <= LaneSize) );
  37. lane.low := {}; lane.high := {};
  38. S.MOVE( ADDRESSOF( data[dataOffset] ), ADDRESSOF( lane ) + laneOffset, length );
  39. ToBitInterleaving( lane, lane );
  40. state[laneNo].low := state[laneNo].low / lane.low;
  41. state[laneNo].high := state[laneNo].high / lane.high;
  42. END XORBytesInLane;
  43. PROCEDURE XORLanes*( CONST data: ARRAY OF CHAR; offset, laneCount: LONGINT );
  44. VAR
  45. lane: Lane; laneNo: LONGINT;
  46. BEGIN
  47. ASSERT( laneCount <= nrLanes );
  48. FOR laneNo := 0 TO laneCount - 1 DO
  49. S.MOVE( ADDRESSOF( data[offset + laneNo*LaneSize] ), ADDRESSOF( lane ), LaneSize );
  50. ToBitInterleaving( lane, lane );
  51. state[laneNo].low := state[laneNo].low / lane.low;
  52. state[laneNo].high := state[laneNo].high / lane.high;
  53. END
  54. END XORLanes;
  55. PROCEDURE ComplementBit*( position: LONGINT );
  56. VAR
  57. laneNo, bit: LONGINT;
  58. BEGIN
  59. ASSERT( position < 1600 );
  60. laneNo := position DIV 64; bit := position MOD 64;
  61. IF bit < 32 THEN
  62. state[laneNo].low := SET32( state[laneNo].low / {bit} )
  63. ELSE
  64. state[laneNo].high := SET32( state[laneNo].high / {bit - 32} );
  65. END
  66. END ComplementBit;
  67. PROCEDURE ExtractBytesInLane*( laneNo, laneOffset, length: LONGINT; VAR data: ARRAY OF CHAR; dataOffset: LONGINT );
  68. VAR
  69. lane: Lane;
  70. BEGIN
  71. ASSERT( (laneNo < nrLanes) & (laneOffset < LaneSize) & (laneOffset+length <= LaneSize) );
  72. FromBitInterleaving( state[laneNo], lane );
  73. S.MOVE( ADDRESSOF( lane ) + laneOffset, ADDRESSOF( data[dataOffset] ), length )
  74. END ExtractBytesInLane;
  75. PROCEDURE ExtractLanes*( VAR data: ARRAY OF CHAR; offset, laneCount: LONGINT );
  76. VAR
  77. lane: Lane; laneNo: LONGINT;
  78. BEGIN
  79. ASSERT( laneCount <= nrLanes );
  80. FOR laneNo := 0 TO laneCount - 1 DO
  81. FromBitInterleaving(state[laneNo], lane );
  82. S.MOVE( ADDRESSOF( lane ), ADDRESSOF( data[offset + laneNo*LaneSize] ), LaneSize )
  83. END
  84. END ExtractLanes;
  85. PROCEDURE XORPermute*( CONST inData: ARRAY OF CHAR; offset, count: LONGINT );
  86. BEGIN
  87. XORLanes( inData, offset, count );
  88. Permute;
  89. END XORPermute;
  90. PROCEDURE XORPermuteExtract*( CONST inData: ARRAY OF CHAR; inOffset, inLaneCount: LONGINT;
  91. VAR outData: ARRAY OF CHAR; outOffset, outLaneCount: LONGINT );
  92. BEGIN
  93. XORLanes( inData, inOffset, inLaneCount );
  94. Permute;
  95. ExtractLanes( outData, outOffset, outLaneCount )
  96. END XORPermuteExtract;
  97. PROCEDURE Permute*;
  98. VAR r: LONGINT;
  99. BEGIN
  100. FOR r := 0 TO nrRounds-1 DO Round( state, r ) END
  101. END Permute;
  102. END Instance;
  103. (* Credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 *)
  104. PROCEDURE ToBitInterleaving( CONST in: Lane; VAR out: Lane );
  105. VAR temp, temp0, temp1: SET32;
  106. BEGIN
  107. temp0 := in.low;
  108. temp1 := in.high;
  109. temp := (temp0 / LSH( temp0, -1 )) * S.VAL( SET32, 022222222H ); temp0 := temp0 / temp / LSH( temp, 1 );
  110. temp := (temp0 / LSH( temp0, -2 )) * S.VAL( SET32, 00C0C0C0CH ); temp0 := temp0 / temp / LSH( temp, 2 );
  111. temp := (temp0 / LSH( temp0, -4 )) * S.VAL( SET32, 000F000F0H ); temp0 := temp0 / temp / LSH( temp, 4 );
  112. temp := (temp0 / LSH( temp0, -8 )) * S.VAL( SET32, 00000FF00H ); temp0 := temp0 / temp / LSH( temp, 8 );
  113. temp := (temp1 / LSH( temp1, -1 )) * S.VAL( SET32, 022222222H ); temp1 := temp1 / temp / LSH( temp, 1 );
  114. temp := (temp1 / LSH( temp1, -2 )) * S.VAL( SET32, 00C0C0C0CH ); temp1 := temp1 / temp / LSH( temp, 2 );
  115. temp := (temp1 / LSH( temp1, -4 )) * S.VAL( SET32, 000F000F0H ); temp1 := temp1 / temp / LSH( temp, 4 );
  116. temp := (temp1 / LSH( temp1, -8 )) * S.VAL( SET32, 00000FF00H ); temp1 := temp1 / temp / LSH( temp, 8 );
  117. out.low := (temp0 * S.VAL( SET32, 00000FFFFH )) + LSH( temp1, 16 );
  118. out.high := LSH( temp0, - 16) + (temp1 * S.VAL( SET32, 0FFFF0000H ));
  119. END ToBitInterleaving;
  120. (* Credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 *)
  121. PROCEDURE FromBitInterleaving( CONST in: Lane; VAR out: Lane );
  122. VAR temp, temp0, temp1: SET32;
  123. BEGIN
  124. temp0 := in.low;
  125. temp1 := in.high;
  126. temp := (temp0 * S.VAL( SET32, 00000FFFFH )) + LSH( temp1, 16 );
  127. temp1 := LSH( temp0, - 16) + (temp1 * S.VAL( SET32, 0FFFF0000H ));
  128. temp0 := temp;
  129. temp := (temp0 / LSH( temp0, -8 )) * S.VAL( SET32, 00000FF00H ); temp0 := temp0 / temp / LSH( temp, 8 );
  130. temp := (temp0 / LSH( temp0, -4 )) * S.VAL( SET32, 000F000F0H ); temp0 := temp0 / temp / LSH( temp, 4 );
  131. temp := (temp0 / LSH( temp0, -2 )) * S.VAL( SET32, 00C0C0C0CH ); temp0 := temp0 / temp / LSH( temp, 2 );
  132. temp := (temp0 / LSH( temp0, -1 )) * S.VAL( SET32, 022222222H ); temp0 := temp0 / temp / LSH( temp, 1 );
  133. temp := (temp1 / LSH( temp1, -8 )) * S.VAL( SET32, 00000FF00H ); temp1 := temp1 / temp / LSH( temp, 8 );
  134. temp := (temp1 / LSH( temp1, -4 )) * S.VAL( SET32, 000F000F0H ); temp1 := temp1 / temp / LSH( temp, 4 );
  135. temp := (temp1 / LSH( temp1, -2 )) * S.VAL( SET32, 00C0C0C0CH ); temp1 := temp1 / temp / LSH( temp, 2 );
  136. temp := (temp1 / LSH( temp1, -1 )) * S.VAL( SET32, 022222222H ); temp1 := temp1 / temp / LSH( temp, 1 );
  137. out.low := temp0;
  138. out.high := temp1;
  139. END FromBitInterleaving;
  140. PROCEDURE ROL64( VAR lane: Lane; offset: LONGINT );
  141. VAR tmp: SET32;
  142. BEGIN
  143. IF ODD( offset ) THEN
  144. tmp := lane.low;
  145. lane.low := ROT( lane.high, (offset+1) DIV 2 );
  146. lane.high := ROT( tmp, (offset-1) DIV 2 )
  147. ELSE
  148. lane.low := ROT( lane.low, offset DIV 2 );
  149. lane.high := ROT( lane.high, offset DIV 2 )
  150. END;
  151. END ROL64;
  152. PROCEDURE ROL64_1XOR( CONST in1, in2: Lane; VAR out: Lane );
  153. BEGIN
  154. out.low := ROT( in1.high, 1 ) / in2.low;
  155. out.high := in1.low / in2.high;
  156. END ROL64_1XOR;
  157. PROCEDURE Round( VAR a: State; r: LONGINT );
  158. VAR
  159. x, y, i, i1, i2: LONGINT;
  160. c, d: ARRAY 5 OF Lane;
  161. a0: State;
  162. BEGIN
  163. (* theta *)
  164. FOR x := 0 TO 4 DO
  165. c[x].low := {}; c[x].high := {};
  166. FOR y := 0 TO 20 BY 5 DO
  167. c[x].low := c[x].low / a[x+y].low;
  168. c[x].high := c[x].high / a[x+y].high;
  169. END
  170. END;
  171. FOR x := 0 TO 4 DO
  172. ROL64_1XOR( c[(x+1) MOD 5], c[(x+4) MOD 5], d[x] );
  173. END;
  174. FOR x := 0 TO 4 DO
  175. FOR y := 0 TO 4 DO
  176. i := x + 5*y;
  177. a[i].low := a[i].low / d[x].low;
  178. a[i].high := a[i].high / d[x].high
  179. END
  180. END;
  181. (* rho *)
  182. FOR i := 0 TO 24 DO
  183. ROL64( a[i], rhoOffsets[i] );
  184. END;
  185. (* pi *)
  186. a0 := a;
  187. FOR x := 0 TO 4 DO
  188. FOR y := 0 TO 4 DO
  189. a[y + 5*((2*x + 3*y) MOD 5)] := a0[x + 5*y]
  190. END
  191. END;
  192. (* chi *)
  193. FOR y := 0 TO 20 BY 5 DO
  194. FOR x := 0 TO 2 DO
  195. i := x + y; i1 := x + 1 + y; i2 := x + 2 + y;
  196. c[x].low := a[i].low / ((-a[i1].low) * a[i2].low);
  197. c[x].high := a[i].high / ((-a[i1].high) * a[i2].high);
  198. END;
  199. i := 3 + y; i1 := 4 + y; i2 := 0 + y;
  200. c[3].low := a[i].low / ((-a[i1].low) * a[i2].low);
  201. c[3].high := a[i].high / ((-a[i1].high) * a[i2].high);
  202. i := 4 + y; i1 := 0 + y; i2 := 1 + y;
  203. c[4].low := a[i].low / ((-a[i1].low) * a[i2].low);
  204. c[4].high := a[i].high / ((-a[i1].high) * a[i2].high);
  205. FOR x := 0 TO 4 DO
  206. a[x+y].low := c[x].low;
  207. a[x+y].high := c[x].high
  208. END
  209. END;
  210. (* iota *)
  211. a[0].low := a[0].low / roundConstants[r].low;
  212. a[0].high := a[0].high / roundConstants[r].high;
  213. END Round;
  214. (* ---------------------------------------------------------------- *)
  215. PROCEDURE InitializeRoundConstants;
  216. VAR
  217. LFSRstate: SET32;
  218. i, j, bit: LONGINT;
  219. lane: Lane;
  220. BEGIN
  221. LFSRstate := {0};
  222. FOR i := 0 TO nrRounds - 1 DO
  223. lane.low := {}; lane.high := {};
  224. FOR j := 0 TO 6 DO
  225. bit := ASH( 1, j ) - 1;
  226. IF LFSR86540( LFSRstate ) THEN
  227. IF bit < 32 THEN INCL( lane.low, bit ) ELSE INCL( lane.high, bit - 32 ) END
  228. END
  229. END;
  230. ToBitInterleaving( lane, roundConstants[i] );
  231. END
  232. END InitializeRoundConstants;
  233. PROCEDURE InitializeRhoOffsets;
  234. VAR
  235. x, y, t, oldY: LONGINT;
  236. BEGIN
  237. rhoOffsets[0] := 0;
  238. x := 1;
  239. y := 0;
  240. FOR t := 0 TO 23 DO
  241. rhoOffsets[x + 5*y] := ((t+1)*(t+2) DIV 2) MOD 64;
  242. oldY := y; y := (2*x + 3*y) MOD 5;
  243. x := oldY;
  244. END
  245. END InitializeRhoOffsets;
  246. PROCEDURE LFSR86540( VAR LFSR: SET32 ): BOOLEAN;
  247. VAR result: BOOLEAN;
  248. BEGIN
  249. result := 0 IN LFSR;
  250. IF 7 IN LFSR THEN
  251. (* Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1 *)
  252. LFSR := LSH( LFSR, 1) / S.VAL( SET32, 71H );
  253. ELSE
  254. LFSR := LSH( LFSR, 1 )
  255. END;
  256. RETURN result;
  257. END LFSR86540;
  258. BEGIN
  259. InitializeRoundConstants;
  260. InitializeRhoOffsets;
  261. END CryptoKeccakF1600.