xref: /freebsd/crypto/libecc/include/libecc/hash/keccak.h (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  */
16 #ifndef __KECCAK_H__
17 #define __KECCAK_H__
18 
19 #include <libecc/words/words.h>
20 
21 #define _KECCAK_ROTL_(x, y) (((x) << (y)) | ((x) >> ((sizeof(u64) * 8) - (y))))
22 
23 /* We handle the case where one of the shifts is more than 64-bit: in this
24  * case, behaviour is undefined as per ANSI C definition. In this case, we
25  * return the untouched input.
26  */
27 #define KECCAK_ROTL(x, y) ((((y) < (sizeof(u64) * 8)) && ((y) > 0)) ? (_KECCAK_ROTL_(x, y)) : (x))
28 
29 /*
30  * Round transformation of the state. Notations are the
31  * same as the ones used in:
32  * http://keccak.noekeon.org/specs_summary.html
33  */
34 #define KECCAK_WORD_LOG 6
35 #define KECCAK_ROUNDS   (12 + (2 * KECCAK_WORD_LOG))
36 #define KECCAK_SLICES   5
37 
38 static const u64 keccak_rc[KECCAK_ROUNDS] =
39 {
40 	0x0000000000000001ULL, 0x0000000000008082ULL,
41 	0x800000000000808AULL, 0x8000000080008000ULL,
42 	0x000000000000808BULL, 0x0000000080000001ULL,
43 	0x8000000080008081ULL, 0x8000000000008009ULL,
44 	0x000000000000008AULL, 0x0000000000000088ULL,
45 	0x0000000080008009ULL, 0x000000008000000AULL,
46 	0x000000008000808BULL, 0x800000000000008BULL,
47 	0x8000000000008089ULL, 0x8000000000008003ULL,
48 	0x8000000000008002ULL, 0x8000000000000080ULL,
49 	0x000000000000800AULL, 0x800000008000000AULL,
50 	0x8000000080008081ULL, 0x8000000000008080ULL,
51 	0x0000000080000001ULL, 0x8000000080008008ULL
52 };
53 
54 static const u8 keccak_rot[KECCAK_SLICES][KECCAK_SLICES] =
55 {
56 	{  0, 36,  3, 41, 18 },
57 	{  1, 44, 10, 45,  2 },
58 	{ 62,  6, 43, 15, 61 },
59 	{ 28, 55, 25, 21, 56 },
60 	{ 27, 20, 39,  8, 14 },
61 };
62 
63 
64 /* Macro to handle endianness conversion */
65 #define SWAP64_Idx(a)   ((sizeof(u64) * ((u8)(a) / sizeof(u64))) + (sizeof(u64) - 1 - ((u8)(a) % sizeof(u64))))
66 
67 #define Idx_slices(x, y)	((x) + (KECCAK_SLICES * (y)))
68 #define Idx(A, x, y)		((A)[Idx_slices(x, y)])
69 
70 #define KECCAKROUND(A, RC) do {								\
71 	int x, y;									\
72 	u64 tmp;									\
73 	/* Temporary B, C and D arrays */						\
74 	u64 BCD[KECCAK_SLICES * KECCAK_SLICES];						\
75 	/* Theta step */								\
76 	for(x = 0; x < KECCAK_SLICES; x++){						\
77 		Idx(BCD, x, 0) = Idx(A, x, 0) ^ Idx(A, x, 1) ^ Idx(A, x, 2) ^		\
78 				 Idx(A, x, 3) ^ Idx(A, x, 4);				\
79 	}										\
80 	for(x = 0; x < KECCAK_SLICES; x++){						\
81 		tmp = Idx(BCD, (x + 4) % 5, 0) ^					\
82 		      KECCAK_ROTL(Idx(BCD, (x + 1) % 5, 0), 1);				\
83 		for(y = 0; y < KECCAK_SLICES; y++){					\
84 			Idx(A, x, y) ^= tmp;						\
85 		}									\
86 	}										\
87 	/* Rho and Pi steps */								\
88 	for(x = 0; x < KECCAK_SLICES; x++){						\
89 		for(y = 0; y < KECCAK_SLICES; y++){					\
90 			Idx(BCD, y, ((2*x)+(3*y)) % 5) =				\
91 			KECCAK_ROTL(Idx(A, x, y), keccak_rot[x][y]);			\
92 		}									\
93 	}										\
94 	/* Chi step */									\
95 	for(x = 0; x < KECCAK_SLICES; x++){						\
96 		for(y = 0; y < KECCAK_SLICES; y++){					\
97 			Idx(A, x, y) = Idx(BCD, x, y) ^					\
98 				(~Idx(BCD, (x+1) % 5, y) & Idx(BCD, (x+2)%5, y));	\
99 		}									\
100 	}										\
101 	/* Iota step */									\
102 	Idx(A, 0, 0) ^= (RC);								\
103 } while(0)
104 
105 #define KECCAKF(A) do {									\
106 	int round;									\
107 	for(round = 0; round < KECCAK_ROUNDS; round++){					\
108 		KECCAKROUND(A, keccak_rc[round]);					\
109 	}										\
110 } while(0)
111 
112 #endif /* __KECCAK_H__ */
113