xref: /freebsd/crypto/libecc/include/libecc/hash/bash.h (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1 /*
2  *  Copyright (C) 2022 - 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  *
8  *  This software is licensed under a dual BSD and GPL v2 license.
9  *  See LICENSE file at the root folder of the project.
10  */
11 #ifndef __BASH_H__
12 #define __BASH_H__
13 
14 #include <libecc/words/words.h>
15 
16 /*
17  * This is an implementation of the BASH hash functions family (for sizes 224, 256, 384 and 512)
18  * following the standard STB 34.101.77-2020 (http://apmi.bsu.by/assets/files/std/bash-spec24.pdf).
19  * An english version of the specifications exist here: https://eprint.iacr.org/2016/587.pdf
20  */
21 
22 #define _BASH_ROTHI_(x, y) (((x) << (y)) | ((x) >> ((sizeof(u64) * 8) - (y))))
23 
24 /* We handle the case where one of the shifts is more than 64-bit: in this
25  * case, behaviour is undefined as per ANSI C definition. In this case, we
26  * return the untouched input.
27  */
28 #define BASH_ROTHI(x, y) ((((y) < (sizeof(u64) * 8)) && ((y) > 0)) ? (_BASH_ROTHI_(x, y)) : (x))
29 
30 /*
31  * Round transformation of the state. Notations are the
32  * same as the ones used in:
33  * https://eprint.iacr.org/2016/587.pdf
34  */
35 #define BASH_SLICES_X   3
36 #define BASH_SLICES_Y   8
37 #define BASH_ROT_ROUNDS 8
38 #define BASH_ROT_IDX    4
39 #define BASH_ROUNDS     24
40 
41 #define BASH_L3_S3(W0, W1, W2, m1, n1, m2, n2) do {				\
42 	u64 T0, T1, T2;								\
43 	T0 = BASH_ROTHI(W0, m1);						\
44 	W0 = (W0 ^ W1 ^ W2);							\
45 	T1 = (W1 ^ BASH_ROTHI(W0, n1));						\
46 	W1 = (T0 ^ T1);								\
47 	W2 = (W2 ^ BASH_ROTHI(W2, m2) ^ BASH_ROTHI(T1, n2));			\
48 	T0 = (~(W2));								\
49 	T1 = (W0 | W2);								\
50 	T2 = (W0 & W1);								\
51 	T0 = (T0 | W1);								\
52 	W1 = (W1 ^ T1);								\
53 	W2 = (W2 ^ T2);								\
54 	W0 = (W0 ^ T0);								\
55 } while(0)
56 
57 #define BASH_PERMUTE(S) do {							\
58 	u64 S_[BASH_SLICES_X * BASH_SLICES_Y];					\
59 	IGNORE_RET_VAL(local_memcpy(S_, S, sizeof(S_)));			\
60 	S[ 0] = S_[15]; S[ 1] = S_[10]; S[ 2] = S_[ 9]; S[ 3] = S_[12];		\
61 	S[ 4] = S_[11]; S[ 5] = S_[14]; S[ 6] = S_[13]; S[ 7] = S_[ 8];		\
62 	S[ 8] = S_[17]; S[ 9] = S_[16]; S[10] = S_[19]; S[11] = S_[18];		\
63 	S[12] = S_[21]; S[13] = S_[20]; S[14] = S_[23]; S[15] = S_[22];		\
64 	S[16] = S_[ 6]; S[17] = S_[ 3]; S[18] = S_[ 0]; S[19] = S_[ 5];		\
65 	S[20] = S_[ 2]; S[21] = S_[ 7]; S[22] = S_[ 4]; S[23] = S_[ 1];		\
66 } while(0)
67 
68 static const u64 bash_rc[BASH_ROUNDS] =
69 {
70 	0x3bf5080ac8ba94b1ULL,
71 	0xc1d1659c1bbd92f6ULL,
72 	0x60e8b2ce0ddec97bULL,
73 	0xec5fb8fe790fbc13ULL,
74 	0xaa043de6436706a7ULL,
75 	0x8929ff6a5e535bfdULL,
76 	0x98bf1e2c50c97550ULL,
77 	0x4c5f8f162864baa8ULL,
78 	0x262fc78b14325d54ULL,
79 	0x1317e3c58a192eaaULL,
80 	0x098bf1e2c50c9755ULL,
81 	0xd8ee19681d669304ULL,
82 	0x6c770cb40eb34982ULL,
83 	0x363b865a0759a4c1ULL,
84 	0xc73622b47c4c0aceULL,
85 	0x639b115a3e260567ULL,
86 	0xede6693460f3da1dULL,
87 	0xaad8d5034f9935a0ULL,
88 	0x556c6a81a7cc9ad0ULL,
89 	0x2ab63540d3e64d68ULL,
90 	0x155b1aa069f326b4ULL,
91 	0x0aad8d5034f9935aULL,
92 	0x0556c6a81a7cc9adULL,
93 	0xde8082cd72debc78ULL,
94 };
95 
96 static const u8 bash_rot[BASH_ROT_ROUNDS][BASH_ROT_IDX] =
97 {
98 	{  8, 53, 14,  1 },
99 	{ 56, 51, 34,  7 },
100 	{  8, 37, 46, 49 },
101 	{ 56,  3,  2, 23 },
102 	{  8, 21, 14, 33 },
103 	{ 56, 19, 34, 39 },
104 	{  8,  5, 46, 17 },
105 	{ 56, 35,  2, 55 },
106 };
107 
108 /* Macro to handle endianness conversion */
109 #define SWAP64(A) do {								\
110 	A = ((A) << 56 | ((A) & 0xff00) << 40 | ((A) & 0xff0000) << 24 |	\
111 	    ((A) & 0xff000000) << 8 | ((A) >> 8 & 0xff000000) |			\
112 	    ((A) >> 24 & 0xff0000) | ((A) >> 40 & 0xff00) | (A) >> 56);		\
113 } while(0)
114 
115 /* The main Bash-f core as descibed in the specification. */
116 #define BASHF(S, end) do {									\
117 	unsigned int round, i;									\
118 	/* Swap endianness if necessary */							\
119 	if(end == BASH_BIG){									\
120 		for(i = 0; i < (BASH_SLICES_X * BASH_SLICES_Y); i++){				\
121 			SWAP64(S[i]);								\
122 		}										\
123 	}											\
124 	for(round = 0; round < BASH_ROUNDS; round++){						\
125 		unsigned int v;									\
126 		for(v = 0; v < 8; v++){								\
127 			BASH_L3_S3(S[v], S[v+8], S[v+16], bash_rot[v][0], bash_rot[v][1],	\
128 							bash_rot[v][2], bash_rot[v][3]);	\
129 		}										\
130 		BASH_PERMUTE(S);								\
131 		S[23] ^= bash_rc[round];							\
132 	}											\
133 	/* Swap back endianness if necessary */							\
134 	if(end == BASH_BIG){									\
135 		for(i = 0; i < (BASH_SLICES_X * BASH_SLICES_Y); i++){				\
136 			SWAP64(S[i]);								\
137 		}										\
138 	}											\
139 } while(0)
140 
141 typedef enum {
142 	BASH_LITTLE = 0,
143 	BASH_BIG = 1,
144 } bash_endianness;
145 
146 typedef struct bash_context_ {
147 	u8 bash_digest_size;
148 	u8 bash_block_size;
149 	bash_endianness bash_endian;
150 	/* Local counter */
151 	u64 bash_total;
152 	/* Bash state */
153 	u64 bash_state[BASH_SLICES_X * BASH_SLICES_Y];
154 	/* Initialization magic value */
155 	u64 magic;
156 } bash_context;
157 
158 ATTRIBUTE_WARN_UNUSED_RET int _bash_init(bash_context *ctx, uint8_t digest_size);
159 ATTRIBUTE_WARN_UNUSED_RET int _bash_update(bash_context *ctx, const uint8_t *buf, uint32_t buflen);
160 ATTRIBUTE_WARN_UNUSED_RET int _bash_finalize(bash_context *ctx, uint8_t *output);
161 
162 #endif /* __BASH_H__ */
163