xref: /src/crypto/libecc/scripts/sha3.py (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1736d6639SKyle Evans#/*
2736d6639SKyle Evans# *  Copyright (C) 2017 - This file is part of libecc project
3736d6639SKyle Evans# *
4736d6639SKyle Evans# *  Authors:
5736d6639SKyle Evans# *      Ryad BENADJILA <ryadbenadjila@gmail.com>
6736d6639SKyle Evans# *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7736d6639SKyle Evans# *      Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8736d6639SKyle Evans# *
9736d6639SKyle Evans# *  Contributors:
10736d6639SKyle Evans# *      Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11736d6639SKyle Evans# *      Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12736d6639SKyle Evans# *
13736d6639SKyle Evans# *  This software is licensed under a dual BSD and GPL v2 license.
14736d6639SKyle Evans# *  See LICENSE file at the root folder of the project.
15736d6639SKyle Evans# */
16736d6639SKyle Evansimport struct, sys
17736d6639SKyle Evans
18736d6639SKyle Evanskeccak_rc = [
19736d6639SKyle Evans        0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000,
20736d6639SKyle Evans        0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
21736d6639SKyle Evans        0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
22736d6639SKyle Evans        0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003,
23736d6639SKyle Evans        0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A,
24736d6639SKyle Evans        0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
25736d6639SKyle Evans]
26736d6639SKyle Evans
27736d6639SKyle Evanskeccak_rot = [
28736d6639SKyle Evans        [  0, 36,  3, 41, 18 ],
29736d6639SKyle Evans        [  1, 44, 10, 45,  2 ],
30736d6639SKyle Evans        [ 62,  6, 43, 15, 61 ],
31736d6639SKyle Evans        [ 28, 55, 25, 21, 56 ],
32736d6639SKyle Evans        [ 27, 20, 39,  8, 14 ],
33736d6639SKyle Evans]
34736d6639SKyle Evans
35736d6639SKyle Evansdef is_python_2():
36736d6639SKyle Evans    if sys.version_info[0] < 3:
37736d6639SKyle Evans        return True
38736d6639SKyle Evans    else:
39736d6639SKyle Evans        return False
40736d6639SKyle Evans
41736d6639SKyle Evans# Keccak function
42736d6639SKyle Evansdef keccak_rotl(x, l):
43736d6639SKyle Evans	return (((x << l) ^ (x >> (64 - l))) & (2**64-1))
44736d6639SKyle Evans
45736d6639SKyle Evansdef keccakround(bytestate, rc):
46736d6639SKyle Evans	# Import little endian state
47736d6639SKyle Evans	state = [0] * 25
48736d6639SKyle Evans	for i in range(0, 25):
49736d6639SKyle Evans		to_unpack = ''.join(bytestate[(8*i):(8*i)+8])
50736d6639SKyle Evans		if is_python_2() == False:
51736d6639SKyle Evans			to_unpack = to_unpack.encode('latin-1')
52736d6639SKyle Evans		(state[i],) = struct.unpack('<Q', to_unpack)
53736d6639SKyle Evans	# Proceed with the KECCAK core
54736d6639SKyle Evans	bcd = [0] * 25
55736d6639SKyle Evans	# Theta
56736d6639SKyle Evans	for i in range(0, 5):
57736d6639SKyle Evans		bcd[i] = state[i] ^ state[i + (5*1)] ^ state[i + (5*2)] ^ state[i + (5*3)] ^ state[i + (5*4)]
58736d6639SKyle Evans
59736d6639SKyle Evans	for i in range(0, 5):
60736d6639SKyle Evans		tmp = bcd[(i+4)%5] ^ keccak_rotl(bcd[(i+1)%5], 1)
61736d6639SKyle Evans		for j in range(0, 5):
62736d6639SKyle Evans			state[i + (5 * j)] = state[i + (5 * j)] ^ tmp
63736d6639SKyle Evans	# Rho and Pi
64736d6639SKyle Evans	for i in range(0, 5):
65736d6639SKyle Evans		for j in range(0, 5):
66736d6639SKyle Evans			bcd[j + (5*(((2*i)+(3*j)) % 5))] = keccak_rotl(state[i + (5*j)], keccak_rot[i][j])
67736d6639SKyle Evans	# Chi
68736d6639SKyle Evans	for i in range(0, 5):
69736d6639SKyle Evans		for j in range(0, 5):
70736d6639SKyle Evans			state[i + (5*j)] = bcd[i + (5*j)] ^ (~bcd[((i+1)%5) + (5*j)] & bcd[((i+2)%5) + (5*j)])
71736d6639SKyle Evans	# Iota
72736d6639SKyle Evans	state[0] = state[0] ^ keccak_rc[rc]
73736d6639SKyle Evans	# Pack the output state
74736d6639SKyle Evans	output = [0] * (25 * 8)
75736d6639SKyle Evans	for i in range(0, 25):
76736d6639SKyle Evans		packed = struct.pack('<Q', state[i])
77736d6639SKyle Evans		if is_python_2() == True:
78736d6639SKyle Evans			output[(8*i):(8*i)+1] = packed
79736d6639SKyle Evans		else:
80736d6639SKyle Evans			output[(8*i):(8*i)+1] = packed.decode('latin-1')
81736d6639SKyle Evans	return output
82736d6639SKyle Evans
83736d6639SKyle Evansdef keccakf(bytestate):
84736d6639SKyle Evans	for rnd in range(0, 24):
85736d6639SKyle Evans		bytestate = keccakround(bytestate, rnd)
86736d6639SKyle Evans	return bytestate
87736d6639SKyle Evans
88736d6639SKyle Evans# SHA-3 context class
89736d6639SKyle Evansclass Sha3_ctx(object):
90736d6639SKyle Evans	def __init__(self, digest_size):
91736d6639SKyle Evans		self.digest_size = digest_size / 8
92736d6639SKyle Evans		self.block_size = (25*8) - (2 * (digest_size / 8))
93736d6639SKyle Evans		self.idx = 0
94736d6639SKyle Evans		self.state = [chr(0)] * (25 * 8)
95736d6639SKyle Evans	def digest_size(self):
96736d6639SKyle Evans		return self.digest_size
97736d6639SKyle Evans	def block_size(self):
98736d6639SKyle Evans		return self.block_size
99736d6639SKyle Evans	def update(self, message):
100736d6639SKyle Evans		if (is_python_2() == False):
101736d6639SKyle Evans			message = message.decode('latin-1')
102736d6639SKyle Evans		for i in range(0, len(message)):
103736d6639SKyle Evans			self.state[self.idx] = chr(ord(self.state[self.idx]) ^ ord(message[i]))
104736d6639SKyle Evans			self.idx = self.idx + 1
105736d6639SKyle Evans			if (self.idx == self.block_size):
106736d6639SKyle Evans				self.state = keccakf(self.state)
107736d6639SKyle Evans				self.idx = 0
108736d6639SKyle Evans	def digest(self):
109736d6639SKyle Evans		self.state[self.idx] = chr(ord(self.state[self.idx]) ^ 0x06)
110736d6639SKyle Evans		self.state[int(self.block_size - 1)] = chr(ord(self.state[int(self.block_size - 1)]) ^ 0x80)
111736d6639SKyle Evans		self.state = keccakf(self.state)
112736d6639SKyle Evans		digest = ''.join(self.state[:int(self.digest_size)])
113736d6639SKyle Evans		if is_python_2() == False:
114736d6639SKyle Evans			digest = digest.encode('latin-1')
115736d6639SKyle Evans		return digest
116