/ external / libecc / scripts / sha3.py
sha3.py
  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  # */
 16  import struct, sys
 17  
 18  keccak_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  
 27  keccak_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  
 35  def is_python_2():
 36      if sys.version_info[0] < 3:
 37          return True
 38      else:
 39          return False
 40  
 41  # Keccak function
 42  def keccak_rotl(x, l):
 43  	return (((x << l) ^ (x >> (64 - l))) & (2**64-1))
 44  
 45  def 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  
 83  def keccakf(bytestate):
 84  	for rnd in range(0, 24):
 85  		bytestate = keccakround(bytestate, rnd)	
 86  	return bytestate
 87  
 88  # SHA-3 context class
 89  class 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