xref: /freebsd/crypto/libecc/scripts/sha3.py (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1#/*
2# *  Copyright (C) 2017 - This file is part of libecc project
3# *
4# *  Authors:
5# *      Ryad BENADJILA <ryadbenadjila@gmail.com>
6# *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7# *      Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8# *
9# *  Contributors:
10# *      Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11# *      Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12# *
13# *  This software is licensed under a dual BSD and GPL v2 license.
14# *  See LICENSE file at the root folder of the project.
15# */
16import struct, sys
17
18keccak_rc = [
19        0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000,
20        0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
21        0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
22        0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003,
23        0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A,
24        0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
25]
26
27keccak_rot = [
28        [  0, 36,  3, 41, 18 ],
29        [  1, 44, 10, 45,  2 ],
30        [ 62,  6, 43, 15, 61 ],
31        [ 28, 55, 25, 21, 56 ],
32        [ 27, 20, 39,  8, 14 ],
33]
34
35def is_python_2():
36    if sys.version_info[0] < 3:
37        return True
38    else:
39        return False
40
41# Keccak function
42def keccak_rotl(x, l):
43	return (((x << l) ^ (x >> (64 - l))) & (2**64-1))
44
45def keccakround(bytestate, rc):
46	# Import little endian state
47	state = [0] * 25
48	for i in range(0, 25):
49		to_unpack = ''.join(bytestate[(8*i):(8*i)+8])
50		if is_python_2() == False:
51			to_unpack = to_unpack.encode('latin-1')
52		(state[i],) = struct.unpack('<Q', to_unpack)
53	# Proceed with the KECCAK core
54	bcd = [0] * 25
55	# Theta
56	for i in range(0, 5):
57		bcd[i] = state[i] ^ state[i + (5*1)] ^ state[i + (5*2)] ^ state[i + (5*3)] ^ state[i + (5*4)]
58
59	for i in range(0, 5):
60		tmp = bcd[(i+4)%5] ^ keccak_rotl(bcd[(i+1)%5], 1)
61		for j in range(0, 5):
62			state[i + (5 * j)] = state[i + (5 * j)] ^ tmp
63	# Rho and Pi
64	for i in range(0, 5):
65		for j in range(0, 5):
66			bcd[j + (5*(((2*i)+(3*j)) % 5))] = keccak_rotl(state[i + (5*j)], keccak_rot[i][j])
67	# Chi
68	for i in range(0, 5):
69		for j in range(0, 5):
70			state[i + (5*j)] = bcd[i + (5*j)] ^ (~bcd[((i+1)%5) + (5*j)] & bcd[((i+2)%5) + (5*j)])
71	# Iota
72	state[0] = state[0] ^ keccak_rc[rc]
73	# Pack the output state
74	output = [0] * (25 * 8)
75	for i in range(0, 25):
76		packed = struct.pack('<Q', state[i])
77		if is_python_2() == True:
78			output[(8*i):(8*i)+1] = packed
79		else:
80			output[(8*i):(8*i)+1] = packed.decode('latin-1')
81	return output
82
83def keccakf(bytestate):
84	for rnd in range(0, 24):
85		bytestate = keccakround(bytestate, rnd)
86	return bytestate
87
88# SHA-3 context class
89class Sha3_ctx(object):
90	def __init__(self, digest_size):
91		self.digest_size = digest_size / 8
92		self.block_size = (25*8) - (2 * (digest_size / 8))
93		self.idx = 0
94		self.state = [chr(0)] * (25 * 8)
95	def digest_size(self):
96		return self.digest_size
97	def block_size(self):
98		return self.block_size
99	def update(self, message):
100		if (is_python_2() == False):
101			message = message.decode('latin-1')
102		for i in range(0, len(message)):
103			self.state[self.idx] = chr(ord(self.state[self.idx]) ^ ord(message[i]))
104			self.idx = self.idx + 1
105			if (self.idx == self.block_size):
106				self.state = keccakf(self.state)
107				self.idx = 0
108	def digest(self):
109		self.state[self.idx] = chr(ord(self.state[self.idx]) ^ 0x06)
110		self.state[int(self.block_size - 1)] = chr(ord(self.state[int(self.block_size - 1)]) ^ 0x80)
111		self.state = keccakf(self.state)
112		digest = ''.join(self.state[:int(self.digest_size)])
113		if is_python_2() == False:
114			digest = digest.encode('latin-1')
115		return digest
116