keccak.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. #!/usr/bin/env python3
  2. #
  3. # Python 2 code from here: https://github.com/ctz/keccak
  4. # Ported to python3 by the MMGen Project
  5. #
  6. # This is the old, pre-SHA3 version of Keccak used by Ethereum, which is not supported
  7. # by hashlib.sha3
  8. from math import log
  9. from operator import xor
  10. from copy import deepcopy
  11. from functools import reduce
  12. # The Keccak-f round constants.
  13. RoundConstants = [
  14. 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000,
  15. 0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
  16. 0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
  17. 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003,
  18. 0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A,
  19. 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
  20. ]
  21. RotationConstants = [
  22. [ 0, 1, 62, 28, 27, ],
  23. [ 36, 44, 6, 55, 20, ],
  24. [ 3, 10, 43, 25, 39, ],
  25. [ 41, 45, 15, 21, 8, ],
  26. [ 18, 2, 61, 56, 14, ]
  27. ]
  28. Masks = [(1 << i) - 1 for i in range(65)]
  29. def bits2bytes(x):
  30. return (int(x) + 7) // 8
  31. def rol(value, left, bits):
  32. """
  33. Circularly rotate 'value' to the left,
  34. treating it as a quantity of the given size in bits.
  35. """
  36. top = value >> (bits - left)
  37. bot = (value & Masks[bits - left]) << left
  38. return bot | top
  39. def ror(value, right, bits):
  40. """
  41. Circularly rotate 'value' to the right,
  42. treating it as a quantity of the given size in bits.
  43. """
  44. top = value >> right
  45. bot = (value & Masks[right]) << (bits - right)
  46. return bot | top
  47. def multirate_padding(used_bytes, align_bytes):
  48. """
  49. The Keccak padding function.
  50. """
  51. padlen = align_bytes - used_bytes
  52. if padlen == 0:
  53. padlen = align_bytes
  54. # note: padding done in 'internal bit ordering', wherein LSB is leftmost
  55. if padlen == 1:
  56. return [0x81]
  57. else:
  58. return [0x01] + ([0x00] * (padlen - 2)) + [0x80]
  59. def keccak_f(state):
  60. """
  61. This is Keccak-f permutation. It operates on and
  62. mutates the passed-in KeccakState. It returns nothing.
  63. """
  64. def round(A, RC):
  65. W, H = state.W, state.H
  66. rangeW, rangeH = state.rangeW, state.rangeH
  67. lanew = state.lanew
  68. zero = state.zero
  69. # theta
  70. C = [reduce(xor, A[x]) for x in rangeW]
  71. D = [0] * W
  72. for x in rangeW:
  73. D[x] = C[(x - 1) % W] ^ rol(C[(x + 1) % W], 1, lanew)
  74. for y in rangeH:
  75. A[x][y] ^= D[x]
  76. # rho and pi
  77. B = zero()
  78. for x in rangeW:
  79. for y in rangeH:
  80. B[y % W][(2 * x + 3 * y) % H] = rol(A[x][y], RotationConstants[y][x], lanew)
  81. # chi
  82. for x in rangeW:
  83. for y in rangeH:
  84. A[x][y] = B[x][y] ^ ((~ B[(x + 1) % W][y]) & B[(x + 2) % W][y])
  85. # iota
  86. A[0][0] ^= RC
  87. l = int(log(state.lanew, 2))
  88. nr = 12 + 2 * l
  89. for ir in range(nr):
  90. round(state.s, RoundConstants[ir])
  91. class KeccakState(object):
  92. """
  93. A keccak state container.
  94. The state is stored as a 5x5 table of integers.
  95. """
  96. W = 5
  97. H = 5
  98. rangeW = range(W)
  99. rangeH = range(H)
  100. @staticmethod
  101. def zero():
  102. """
  103. Returns an zero state table.
  104. """
  105. return [[0] * KeccakState.W for x in KeccakState.rangeH]
  106. @staticmethod
  107. def format(st):
  108. """
  109. Formats the given state as hex, in natural byte order.
  110. """
  111. rows = []
  112. def fmt(x): return '%016x' % x
  113. for y in KeccakState.rangeH:
  114. row = []
  115. for x in rangeW:
  116. row.append(fmt(st[x][y]))
  117. rows.append(' '.join(row))
  118. return '\n'.join(rows)
  119. @staticmethod
  120. def lane2bytes(s, w):
  121. """
  122. Converts the lane s to a sequence of byte values,
  123. assuming a lane is w bits.
  124. """
  125. return [(s >> b) & 0xff for b in range(0, w, 8)]
  126. @staticmethod
  127. def bytes2lane(bb):
  128. """
  129. Converts a sequence of byte values to a lane.
  130. """
  131. r = 0
  132. for b in reversed(bb):
  133. r = r << 8 | b
  134. return r
  135. def __init__(self, bitrate, b):
  136. self.bitrate = bitrate
  137. self.b = b
  138. # only byte-aligned
  139. assert self.bitrate % 8 == 0
  140. self.bitrate_bytes = bits2bytes(self.bitrate)
  141. assert self.b % 25 == 0
  142. self.lanew = self.b // 25
  143. self.s = KeccakState.zero()
  144. def __str__(self):
  145. return KeccakState.format(self.s)
  146. def absorb(self, bb):
  147. """
  148. Mixes in the given bitrate-length string to the state.
  149. """
  150. assert len(bb) == self.bitrate_bytes
  151. bb += [0] * bits2bytes(self.b - self.bitrate)
  152. i = 0
  153. for y in self.rangeH:
  154. for x in self.rangeW:
  155. self.s[x][y] ^= KeccakState.bytes2lane(bb[i:i + 8])
  156. i += 8
  157. def squeeze(self):
  158. """
  159. Returns the bitrate-length prefix of the state to be output.
  160. """
  161. return self.get_bytes()[:self.bitrate_bytes]
  162. def get_bytes(self):
  163. """
  164. Convert whole state to a byte string.
  165. """
  166. out = [0] * bits2bytes(self.b)
  167. i = 0
  168. for y in self.rangeH:
  169. for x in self.rangeW:
  170. v = KeccakState.lane2bytes(self.s[x][y], self.lanew)
  171. out[i:i+8] = v
  172. i += 8
  173. return out
  174. def set_bytes(self, bb):
  175. """
  176. Set whole state from byte string, which is assumed
  177. to be the correct length.
  178. """
  179. i = 0
  180. for y in self.rangeH:
  181. for x in self.rangeW:
  182. self.s[x][y] = KeccakState.bytes2lane(bb[i:i+8])
  183. i += 8
  184. class KeccakSponge(object):
  185. def __init__(self, bitrate, width, padfn, permfn):
  186. self.state = KeccakState(bitrate, width)
  187. self.padfn = padfn
  188. self.permfn = permfn
  189. self.buffer = []
  190. def copy(self):
  191. return deepcopy(self)
  192. def absorb_block(self, bb):
  193. assert len(bb) == self.state.bitrate_bytes
  194. self.state.absorb(bb)
  195. self.permfn(self.state)
  196. def absorb(self, s):
  197. self.buffer += bytes(s)
  198. while len(self.buffer) >= self.state.bitrate_bytes:
  199. self.absorb_block(self.buffer[:self.state.bitrate_bytes])
  200. self.buffer = self.buffer[self.state.bitrate_bytes:]
  201. def absorb_final(self):
  202. padded = self.buffer + self.padfn(len(self.buffer), self.state.bitrate_bytes)
  203. self.absorb_block(padded)
  204. self.buffer = []
  205. def squeeze_once(self):
  206. rc = self.state.squeeze()
  207. self.permfn(self.state)
  208. return rc
  209. def squeeze(self, l):
  210. Z = self.squeeze_once()
  211. while len(Z) < l:
  212. Z += self.squeeze_once()
  213. return Z[:l]
  214. class KeccakHash(object):
  215. """
  216. The Keccak hash function, with a hashlib-compatible interface.
  217. """
  218. def __init__(self, bitrate_bits, capacity_bits, output_bits):
  219. # our in-absorption sponge. this is never given padding
  220. assert bitrate_bits + capacity_bits in (25, 50, 100, 200, 400, 800, 1600)
  221. self.sponge = KeccakSponge(bitrate_bits, bitrate_bits + capacity_bits,
  222. multirate_padding,
  223. keccak_f)
  224. # hashlib interface members
  225. assert output_bits % 8 == 0
  226. self.digest_size = bits2bytes(output_bits)
  227. self.block_size = bits2bytes(bitrate_bits)
  228. def __repr__(self):
  229. inf = (self.sponge.state.bitrate,
  230. self.sponge.state.b - self.sponge.state.bitrate,
  231. self.digest_size * 8)
  232. return '<KeccakHash with r=%d, c=%d, image=%d>' % inf
  233. def copy(self):
  234. return deepcopy(self)
  235. def update(self, s):
  236. self.sponge.absorb(s)
  237. def digest(self):
  238. finalised = self.sponge.copy()
  239. finalised.absorb_final()
  240. digest = finalised.squeeze(self.digest_size)
  241. return bytes(digest)
  242. def hexdigest(self):
  243. return self.digest().hex()
  244. @staticmethod
  245. def preset(bitrate_bits, capacity_bits, output_bits):
  246. """
  247. Returns a factory function for the given bitrate, sponge capacity and output length.
  248. The function accepts an optional initial input, ala hashlib.
  249. """
  250. def create(initial_input = None):
  251. h = KeccakHash(bitrate_bits, capacity_bits, output_bits)
  252. if initial_input is not None:
  253. h.update(initial_input)
  254. return h
  255. return create
  256. # SHA3 parameter presets
  257. keccak_224 = KeccakHash.preset(1152, 448, 224)
  258. keccak_256 = KeccakHash.preset(1088, 512, 256)
  259. keccak_384 = KeccakHash.preset(832, 768, 384)
  260. keccak_512 = KeccakHash.preset(576, 1024, 512)