xref: /freebsd/crypto/libecc/src/examples/hash/gostr34_11_94.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1*f0865ec9SKyle Evans /*
2*f0865ec9SKyle Evans  *  Copyright (C) 2021 - This file is part of libecc project
3*f0865ec9SKyle Evans  *
4*f0865ec9SKyle Evans  *  Authors:
5*f0865ec9SKyle Evans  *      Ryad BENADJILA <ryadbenadjila@gmail.com>
6*f0865ec9SKyle Evans  *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7*f0865ec9SKyle Evans  *
8*f0865ec9SKyle Evans  *  This software is licensed under a dual BSD and GPL v2 license.
9*f0865ec9SKyle Evans  *  See LICENSE file at the root folder of the project.
10*f0865ec9SKyle Evans  */
11*f0865ec9SKyle Evans #include "gostr34_11_94.h"
12*f0865ec9SKyle Evans 
13*f0865ec9SKyle Evans /* The 8 4-bit GOST block cipher encryption SBOX */
14*f0865ec9SKyle Evans static const u8 gostr34_11_94_sbox_norm[8][16] =
15*f0865ec9SKyle Evans {
16*f0865ec9SKyle Evans 	{  4, 10,  9,  2, 13,  8,  0, 14,  6, 11,  1, 12,  7, 15,  5,  3 },
17*f0865ec9SKyle Evans 	{ 14, 11,  4, 12,  6, 13, 15, 10,  2,  3,  8,  1,  0,  7,  5,  9 },
18*f0865ec9SKyle Evans 	{  5,  8,  1, 13, 10,  3,  4,  2, 14, 15, 12,  7,  6,  0,  9, 11 },
19*f0865ec9SKyle Evans 	{  7, 13, 10,  1,  0,  8,  9, 15, 14,  4,  6, 12, 11,  2,  5,  3 },
20*f0865ec9SKyle Evans 	{  6, 12,  7,  1,  5, 15, 13,  8,  4, 10,  9, 14,  0,  3, 11,  2 },
21*f0865ec9SKyle Evans 	{  4, 11, 10,  0,  7,  2,  1, 13,  3,  6,  8,  5,  9, 12, 15, 14 },
22*f0865ec9SKyle Evans 	{ 13, 11,  4,  1,  3, 15,  5,  9,  0, 10, 14,  7,  6,  8,  2, 12 },
23*f0865ec9SKyle Evans 	{  1, 15, 13,  0,  5,  7, 10,  4,  9,  2,  3, 14,  6, 11,  8, 12 }
24*f0865ec9SKyle Evans };
25*f0865ec9SKyle Evans 
26*f0865ec9SKyle Evans static const u8 gostr34_11_94_sbox_rfc4357[8][16] =
27*f0865ec9SKyle Evans {
28*f0865ec9SKyle Evans 	{ 10,  4,  5,  6,  8,  1,  3,  7, 13, 12, 14,  0,  9,  2, 11, 15},
29*f0865ec9SKyle Evans 	{  5, 15,  4,  0,  2, 13, 11,  9,  1,  7,  6,  3, 12, 14, 10,  8},
30*f0865ec9SKyle Evans 	{  7, 15, 12, 14,  9,  4,  1,  0,  3, 11,  5,  2,  6, 10,  8, 13},
31*f0865ec9SKyle Evans 	{  4, 10,  7, 12,  0, 15,  2,  8, 14,  1,  6,  5, 13, 11,  9,  3},
32*f0865ec9SKyle Evans 	{  7,  6,  4, 11,  9, 12,  2, 10,  1,  8,  0, 14, 15, 13,  3,  5},
33*f0865ec9SKyle Evans 	{  7,  6,  2,  4, 13,  9, 15,  0, 10,  1,  5, 11,  8, 14, 12,  3},
34*f0865ec9SKyle Evans 	{ 13, 14,  4,  1,  7,  0,  5, 10,  3, 12,  8, 15,  6,  2,  9, 11},
35*f0865ec9SKyle Evans 	{  1,  3, 10,  9,  5, 11,  4, 15,  8,  6,  7, 14, 13,  0,  2, 12}
36*f0865ec9SKyle Evans };
37*f0865ec9SKyle Evans 
38*f0865ec9SKyle Evans 
39*f0865ec9SKyle Evans /* Endianness handling */
gostr34_11_94_arch_is_big_endian(void)40*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_arch_is_big_endian(void)
41*f0865ec9SKyle Evans {
42*f0865ec9SKyle Evans 	const u16 val = 0x0102;
43*f0865ec9SKyle Evans 	const u8 *buf = (const u8 *)(&val);
44*f0865ec9SKyle Evans 
45*f0865ec9SKyle Evans 	return (buf[0] == 0x01);
46*f0865ec9SKyle Evans }
47*f0865ec9SKyle Evans 
48*f0865ec9SKyle Evans /* A and P linear transformations */
gostr34_11_94_A(const u64 Y[GOSTR34_11_94_STATE_SIZE],u64 Y_[GOSTR34_11_94_STATE_SIZE])49*f0865ec9SKyle Evans static inline void gostr34_11_94_A(const u64 Y[GOSTR34_11_94_STATE_SIZE], u64 Y_[GOSTR34_11_94_STATE_SIZE])
50*f0865ec9SKyle Evans {
51*f0865ec9SKyle Evans 	u64 y1, y2, y3, y4;
52*f0865ec9SKyle Evans 
53*f0865ec9SKyle Evans 	y1 = Y[3];
54*f0865ec9SKyle Evans 	y2 = Y[2];
55*f0865ec9SKyle Evans 	y3 = Y[1];
56*f0865ec9SKyle Evans 	y4 = Y[0];
57*f0865ec9SKyle Evans 
58*f0865ec9SKyle Evans 	Y_[0] = (y1 ^ y2);
59*f0865ec9SKyle Evans 	Y_[1] = y4;
60*f0865ec9SKyle Evans 	Y_[2] = y3;
61*f0865ec9SKyle Evans 	Y_[3] = y2;
62*f0865ec9SKyle Evans 
63*f0865ec9SKyle Evans 	return;
64*f0865ec9SKyle Evans }
65*f0865ec9SKyle Evans 
gostr34_11_94_P(const u64 Y[GOSTR34_11_94_STATE_SIZE],u64 Y_[GOSTR34_11_94_STATE_SIZE])66*f0865ec9SKyle Evans static inline void gostr34_11_94_P(const u64 Y[GOSTR34_11_94_STATE_SIZE], u64 Y_[GOSTR34_11_94_STATE_SIZE])
67*f0865ec9SKyle Evans {
68*f0865ec9SKyle Evans 	unsigned int i, k;
69*f0865ec9SKyle Evans 
70*f0865ec9SKyle Evans 	const u8 *y = (const u8*)Y;
71*f0865ec9SKyle Evans 	u8 *y_      = (u8*)Y_;
72*f0865ec9SKyle Evans 
73*f0865ec9SKyle Evans 	for(i = 0; i < 4; i++){
74*f0865ec9SKyle Evans 		for(k = 1; k < 9; k++){
75*f0865ec9SKyle Evans 			unsigned int phi_idx = (8 * GOSTR34_11_94_STATE_SIZE) - (i + (4 * (k - 1)));
76*f0865ec9SKyle Evans 			unsigned int phi = ((8 * i) + k);
77*f0865ec9SKyle Evans 			y_[phi_idx - 1] = y[phi - 1];
78*f0865ec9SKyle Evans 		}
79*f0865ec9SKyle Evans 	}
80*f0865ec9SKyle Evans 	return;
81*f0865ec9SKyle Evans }
82*f0865ec9SKyle Evans 
83*f0865ec9SKyle Evans /* GOSTR34_11_94 key generation constants */
84*f0865ec9SKyle Evans static const u64 gostr34_11_94_C[3][GOSTR34_11_94_STATE_SIZE] = {
85*f0865ec9SKyle Evans 	{ 0, 0, 0, 0 },
86*f0865ec9SKyle Evans 	{ 0xff000000ffff00ffULL, 0x00ffff00ff0000ffULL, 0xff00ff00ff00ff00ULL, 0x00ff00ff00ff00ffULL },
87*f0865ec9SKyle Evans 	{ 0, 0, 0, 0 },
88*f0865ec9SKyle Evans };
89*f0865ec9SKyle Evans 
90*f0865ec9SKyle Evans /* GOSTR34_11_94 key generation */
gostr34_11_94_key_generation(const u64 H[GOSTR34_11_94_STATE_SIZE],const u64 M[GOSTR34_11_94_STATE_SIZE],u64 K[4][GOSTR34_11_94_STATE_SIZE])91*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_key_generation(const u64 H[GOSTR34_11_94_STATE_SIZE], const u64 M[GOSTR34_11_94_STATE_SIZE], u64 K[4][GOSTR34_11_94_STATE_SIZE])
92*f0865ec9SKyle Evans {
93*f0865ec9SKyle Evans 	/* U, V, W */
94*f0865ec9SKyle Evans 	u64 U[GOSTR34_11_94_STATE_SIZE], V[GOSTR34_11_94_STATE_SIZE], W[GOSTR34_11_94_STATE_SIZE];
95*f0865ec9SKyle Evans 	unsigned int i, j;
96*f0865ec9SKyle Evans 	int ret;
97*f0865ec9SKyle Evans 
98*f0865ec9SKyle Evans 	/* U = H */
99*f0865ec9SKyle Evans 	ret = local_memcpy(U, H, sizeof(U)); EG(ret, err);
100*f0865ec9SKyle Evans 	/* V = M */
101*f0865ec9SKyle Evans 	ret = local_memcpy(V, M, sizeof(V)); EG(ret, err);
102*f0865ec9SKyle Evans 	/* W = U ^ V */
103*f0865ec9SKyle Evans 	for(j = 0; j < GOSTR34_11_94_STATE_SIZE; j++){
104*f0865ec9SKyle Evans 		W[j] = (U[j] ^ V[j]);
105*f0865ec9SKyle Evans 	}
106*f0865ec9SKyle Evans 	/* K1 = P(W) */
107*f0865ec9SKyle Evans 	gostr34_11_94_P(W, K[0]);
108*f0865ec9SKyle Evans 
109*f0865ec9SKyle Evans 	for(i = 1; i < 4; i++){
110*f0865ec9SKyle Evans 		/* U = A(U) ^ C */
111*f0865ec9SKyle Evans 		gostr34_11_94_A(U, U);
112*f0865ec9SKyle Evans 		for(j = 0; j < GOSTR34_11_94_STATE_SIZE; j++){
113*f0865ec9SKyle Evans 			u64 C;
114*f0865ec9SKyle Evans 			GET_UINT64_LE(C, (const u8*)&gostr34_11_94_C[i - 1][j], 0);
115*f0865ec9SKyle Evans 			U[j] = (u64)(U[j] ^ C);
116*f0865ec9SKyle Evans 		}
117*f0865ec9SKyle Evans 		/* V = A(A(V)) */
118*f0865ec9SKyle Evans 		gostr34_11_94_A(V, V);
119*f0865ec9SKyle Evans 		gostr34_11_94_A(V, V);
120*f0865ec9SKyle Evans 		/* W = U ^ V */
121*f0865ec9SKyle Evans 		for(j = 0; j < GOSTR34_11_94_STATE_SIZE; j++){
122*f0865ec9SKyle Evans 			W[j] = (u64)(U[j] ^ V[j]);
123*f0865ec9SKyle Evans 		}
124*f0865ec9SKyle Evans 		/* Ki = P(W) */
125*f0865ec9SKyle Evans 		gostr34_11_94_P(W, K[i]);
126*f0865ec9SKyle Evans 	}
127*f0865ec9SKyle Evans 
128*f0865ec9SKyle Evans 	ret = 0;
129*f0865ec9SKyle Evans 
130*f0865ec9SKyle Evans err:
131*f0865ec9SKyle Evans 	return ret;
132*f0865ec9SKyle Evans }
133*f0865ec9SKyle Evans 
134*f0865ec9SKyle Evans /* GOSTR34_11_94 state encryption */
gostr34_11_94_block_encryption(const u64 K[GOSTR34_11_94_STATE_SIZE],const u64 P,u64 * E,const u8 sbox[8][16])135*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_block_encryption(const u64 K[GOSTR34_11_94_STATE_SIZE], const u64 P, u64 *E, const u8 sbox[8][16])
136*f0865ec9SKyle Evans {
137*f0865ec9SKyle Evans 	int ret;
138*f0865ec9SKyle Evans 	unsigned int round, i;
139*f0865ec9SKyle Evans 	u32 R_i, L_i, R_i1 = 0, L_i1 = 0;
140*f0865ec9SKyle Evans 	const u8 *p = (const u8*)&P;
141*f0865ec9SKyle Evans 	u8 *e = (u8*)E;
142*f0865ec9SKyle Evans 
143*f0865ec9SKyle Evans 	MUST_HAVE((K != NULL) && (sbox != NULL) && (E != NULL), ret, err);
144*f0865ec9SKyle Evans 
145*f0865ec9SKyle Evans 	/* The encryption is a Feistel network */
146*f0865ec9SKyle Evans 	GET_UINT32_BE(L_i, p, 0);
147*f0865ec9SKyle Evans 	GET_UINT32_BE(R_i, p, 4);
148*f0865ec9SKyle Evans 	for(round = 0; round < 32; round++){
149*f0865ec9SKyle Evans 		u32 sk;
150*f0865ec9SKyle Evans 		const u8 *k = (const u8*)K;
151*f0865ec9SKyle Evans 		u8 *r_i1 = (u8 *)&R_i1;
152*f0865ec9SKyle Evans 
153*f0865ec9SKyle Evans 		/* Key schedule */
154*f0865ec9SKyle Evans 		if(round < 24){
155*f0865ec9SKyle Evans 			GET_UINT32_LE(sk, k, (4 * (round % 8)));
156*f0865ec9SKyle Evans 		}
157*f0865ec9SKyle Evans 		else{
158*f0865ec9SKyle Evans 			GET_UINT32_LE(sk, k, (4 * (7 - (round % 8))));
159*f0865ec9SKyle Evans 		}
160*f0865ec9SKyle Evans 		/*** Feistel round ***/
161*f0865ec9SKyle Evans 		R_i1 = (u32)(R_i + sk); /* add round key */
162*f0865ec9SKyle Evans 		/* SBox layer */
163*f0865ec9SKyle Evans 		for(i = 0; i < 4; i++){
164*f0865ec9SKyle Evans 			unsigned int sb_idx;
165*f0865ec9SKyle Evans 			if(gostr34_11_94_arch_is_big_endian()){
166*f0865ec9SKyle Evans 				sb_idx = (2 * (3 - i));
167*f0865ec9SKyle Evans 			}
168*f0865ec9SKyle Evans 			else{
169*f0865ec9SKyle Evans 				sb_idx = (2 * i);
170*f0865ec9SKyle Evans 			}
171*f0865ec9SKyle Evans 			r_i1[i] = (u8)((sbox[sb_idx + 1][(r_i1[i] & 0xf0) >> 4] << 4) | (sbox[sb_idx][(r_i1[i] & 0x0f)]));
172*f0865ec9SKyle Evans 		}
173*f0865ec9SKyle Evans 		/* Rotation by 11 and XOR with L */
174*f0865ec9SKyle Evans 		R_i1 = (u32)(ROTL_GOSTR34_11_94(R_i1, 11) ^ L_i);
175*f0865ec9SKyle Evans 		/* Feistel */
176*f0865ec9SKyle Evans 		L_i1 = R_i;
177*f0865ec9SKyle Evans 		/* Next round */
178*f0865ec9SKyle Evans 		R_i = R_i1;
179*f0865ec9SKyle Evans 		L_i = L_i1;
180*f0865ec9SKyle Evans 	}
181*f0865ec9SKyle Evans 	/* Output */
182*f0865ec9SKyle Evans 	PUT_UINT32_LE(L_i1, e, 0);
183*f0865ec9SKyle Evans 	PUT_UINT32_LE(R_i1, e, 4);
184*f0865ec9SKyle Evans 
185*f0865ec9SKyle Evans 	ret = 0;
186*f0865ec9SKyle Evans 
187*f0865ec9SKyle Evans err:
188*f0865ec9SKyle Evans 	return ret;
189*f0865ec9SKyle Evans }
190*f0865ec9SKyle Evans 
gostr34_11_94_state_encryption(const u64 K[4][GOSTR34_11_94_STATE_SIZE],const u64 H[GOSTR34_11_94_STATE_SIZE],u64 S[GOSTR34_11_94_STATE_SIZE],const u8 sbox[8][16])191*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_state_encryption(const u64 K[4][GOSTR34_11_94_STATE_SIZE], const u64 H[GOSTR34_11_94_STATE_SIZE], u64 S[GOSTR34_11_94_STATE_SIZE], const u8 sbox[8][16])
192*f0865ec9SKyle Evans {
193*f0865ec9SKyle Evans 	int ret;
194*f0865ec9SKyle Evans 
195*f0865ec9SKyle Evans 
196*f0865ec9SKyle Evans 	MUST_HAVE((GOSTR34_11_94_STATE_SIZE == 4), ret, err);
197*f0865ec9SKyle Evans 	/* Return S = s4 s3 s2 s1 */
198*f0865ec9SKyle Evans 	/* s1 = E(h1, K1) */
199*f0865ec9SKyle Evans 	ret = gostr34_11_94_block_encryption(K[0], H[3], &S[0], sbox); EG(ret, err);
200*f0865ec9SKyle Evans 	/* s2 = E(h2, K2) */
201*f0865ec9SKyle Evans 	ret = gostr34_11_94_block_encryption(K[1], H[2], &S[1], sbox); EG(ret, err);
202*f0865ec9SKyle Evans 	/* s3 = E(h3, K3) */
203*f0865ec9SKyle Evans 	ret = gostr34_11_94_block_encryption(K[2], H[1], &S[2], sbox); EG(ret, err);
204*f0865ec9SKyle Evans 	/* s4 = E(h4, K4) */
205*f0865ec9SKyle Evans 	ret = gostr34_11_94_block_encryption(K[3], H[0], &S[3], sbox); EG(ret, err);
206*f0865ec9SKyle Evans 
207*f0865ec9SKyle Evans 	ret = 0;
208*f0865ec9SKyle Evans 
209*f0865ec9SKyle Evans err:
210*f0865ec9SKyle Evans 	return ret;
211*f0865ec9SKyle Evans }
212*f0865ec9SKyle Evans 
213*f0865ec9SKyle Evans /*
214*f0865ec9SKyle Evans  * NOTE: we use a somehow "artificial" union here in order to deal with
215*f0865ec9SKyle Evans  * possible alignment issues in the gostr34_11_94_state_psi function
216*f0865ec9SKyle Evans  * (as we have to interpret an array of 4 u64 into an array of 16 u16
217*f0865ec9SKyle Evans  *  in order to apply our Psi function).
218*f0865ec9SKyle Evans  */
219*f0865ec9SKyle Evans typedef union {
220*f0865ec9SKyle Evans 	u64 A[GOSTR34_11_94_STATE_SIZE];
221*f0865ec9SKyle Evans 	u16 B[16];
222*f0865ec9SKyle Evans } gostr34_11_94_union;
223*f0865ec9SKyle Evans 
224*f0865ec9SKyle Evans /* GOSTR34_11_94 output transformation */
gostr34_11_94_state_psi(const u64 G[GOSTR34_11_94_STATE_SIZE],u64 G_[GOSTR34_11_94_STATE_SIZE])225*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_state_psi(const u64 G[GOSTR34_11_94_STATE_SIZE], u64 G_[GOSTR34_11_94_STATE_SIZE])
226*f0865ec9SKyle Evans {
227*f0865ec9SKyle Evans 	int ret;
228*f0865ec9SKyle Evans 	unsigned int i;
229*f0865ec9SKyle Evans 	/* Use our unions in order to deal with alignment issues
230*f0865ec9SKyle Evans 	 * (see the rationale above).
231*f0865ec9SKyle Evans 	 */
232*f0865ec9SKyle Evans 	gostr34_11_94_union G_copy;
233*f0865ec9SKyle Evans 	gostr34_11_94_union *g  = &G_copy;
234*f0865ec9SKyle Evans 	gostr34_11_94_union *g_ = (gostr34_11_94_union*)G_;
235*f0865ec9SKyle Evans 
236*f0865ec9SKyle Evans 	/* Better safe than sorry ... */
237*f0865ec9SKyle Evans 	MUST_HAVE((sizeof(gostr34_11_94_union) == (sizeof(u64) * GOSTR34_11_94_STATE_SIZE)), ret, err);
238*f0865ec9SKyle Evans 
239*f0865ec9SKyle Evans 	/* Copy input */
240*f0865ec9SKyle Evans 	ret = local_memcpy(g, G, sizeof(gostr34_11_94_union)); EG(ret, err);
241*f0865ec9SKyle Evans 
242*f0865ec9SKyle Evans 	/* ψ(Γ) = (γ0 ⊕ γ1 ⊕ γ2 ⊕ γ3 ⊕ γ12 ⊕ γ15) γ15 γ14 · · · γ1
243*f0865ec9SKyle Evans 	 * where Γ is split into sixteen 16-bit words, i.e. Γ = γ15 γ14 · · · γ0.
244*f0865ec9SKyle Evans 	 */
245*f0865ec9SKyle Evans 	for(i = 0; i < 15; i++){
246*f0865ec9SKyle Evans 		g_->B[i] = g->B[i + 1];
247*f0865ec9SKyle Evans 	}
248*f0865ec9SKyle Evans 	g_->B[15] = (u16)((g->B[0]) ^ (g->B[1]) ^ (g->B[2]) ^ (g->B[3]) ^ (g->B[12]) ^ (g->B[15]));
249*f0865ec9SKyle Evans 
250*f0865ec9SKyle Evans 	ret = 0;
251*f0865ec9SKyle Evans 
252*f0865ec9SKyle Evans err:
253*f0865ec9SKyle Evans 	return ret;
254*f0865ec9SKyle Evans }
255*f0865ec9SKyle Evans 
gostr34_11_94_state_output_transform(const u64 H[GOSTR34_11_94_STATE_SIZE],const u64 S[GOSTR34_11_94_STATE_SIZE],const u64 M[GOSTR34_11_94_STATE_SIZE],u64 H_[GOSTR34_11_94_STATE_SIZE])256*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_state_output_transform(const u64 H[GOSTR34_11_94_STATE_SIZE], const u64 S[GOSTR34_11_94_STATE_SIZE], const u64 M[GOSTR34_11_94_STATE_SIZE], u64 H_[GOSTR34_11_94_STATE_SIZE])
257*f0865ec9SKyle Evans {
258*f0865ec9SKyle Evans 	unsigned int i;
259*f0865ec9SKyle Evans 	int ret;
260*f0865ec9SKyle Evans 
261*f0865ec9SKyle Evans 	/* Compute psi^12 of S */
262*f0865ec9SKyle Evans 	ret = local_memcpy(H_, S, GOSTR34_11_94_STATE_SIZE * sizeof(u64)); EG(ret, err);
263*f0865ec9SKyle Evans 	for(i = 0; i < 12; i++){
264*f0865ec9SKyle Evans 		ret = gostr34_11_94_state_psi(H_, H_); EG(ret, err);
265*f0865ec9SKyle Evans 	}
266*f0865ec9SKyle Evans 	/* Compute M xor psi^12  */
267*f0865ec9SKyle Evans 	for(i = 0; i < GOSTR34_11_94_STATE_SIZE; i++){
268*f0865ec9SKyle Evans 		u64 m;
269*f0865ec9SKyle Evans 		if(gostr34_11_94_arch_is_big_endian()){
270*f0865ec9SKyle Evans 			GET_UINT64_LE(m, (const u8*)&M[GOSTR34_11_94_STATE_SIZE - i - 1], 0);
271*f0865ec9SKyle Evans 		}
272*f0865ec9SKyle Evans 		else{
273*f0865ec9SKyle Evans 			GET_UINT64_BE(m, (const u8*)&M[GOSTR34_11_94_STATE_SIZE - i - 1], 0);
274*f0865ec9SKyle Evans 		}
275*f0865ec9SKyle Evans 		H_[i] = (u64)(H_[i] ^ m);
276*f0865ec9SKyle Evans 	}
277*f0865ec9SKyle Evans 	ret = gostr34_11_94_state_psi(H_, H_); EG(ret, err);
278*f0865ec9SKyle Evans 	/* Xor it with H */
279*f0865ec9SKyle Evans 	for(i = 0; i < GOSTR34_11_94_STATE_SIZE; i++){
280*f0865ec9SKyle Evans 		u64 h;
281*f0865ec9SKyle Evans 		if(gostr34_11_94_arch_is_big_endian()){
282*f0865ec9SKyle Evans 			GET_UINT64_LE(h, (const u8*)&H[GOSTR34_11_94_STATE_SIZE - i - 1], 0);
283*f0865ec9SKyle Evans 		}
284*f0865ec9SKyle Evans 		else{
285*f0865ec9SKyle Evans 			GET_UINT64_BE(h, (const u8*)&H[GOSTR34_11_94_STATE_SIZE - i - 1], 0);
286*f0865ec9SKyle Evans 		}
287*f0865ec9SKyle Evans 		H_[i] = (u64)(H_[i] ^ h);
288*f0865ec9SKyle Evans 	}
289*f0865ec9SKyle Evans 	/* Now compute psi^61 */
290*f0865ec9SKyle Evans 	for(i = 0; i < 61; i++){
291*f0865ec9SKyle Evans 		ret = gostr34_11_94_state_psi(H_, H_); EG(ret, err);
292*f0865ec9SKyle Evans 	}
293*f0865ec9SKyle Evans 
294*f0865ec9SKyle Evans 	ret = 0;
295*f0865ec9SKyle Evans 
296*f0865ec9SKyle Evans err:
297*f0865ec9SKyle Evans 	return ret;
298*f0865ec9SKyle Evans }
299*f0865ec9SKyle Evans 
300*f0865ec9SKyle Evans /* GOSTR34_11_94 256-bit words summing (a simple adder with carry in constant time) */
gostr34_11_94_256bit_sum(const u64 A[GOSTR34_11_94_STATE_SIZE],const u64 B[GOSTR34_11_94_STATE_SIZE],u64 C[GOSTR34_11_94_STATE_SIZE])301*f0865ec9SKyle Evans static inline void gostr34_11_94_256bit_sum(const u64 A[GOSTR34_11_94_STATE_SIZE], const u64 B[GOSTR34_11_94_STATE_SIZE], u64 C[GOSTR34_11_94_STATE_SIZE])
302*f0865ec9SKyle Evans {
303*f0865ec9SKyle Evans 	unsigned int i;
304*f0865ec9SKyle Evans 	u64 tmp, carry1, carry2, _carry;
305*f0865ec9SKyle Evans 
306*f0865ec9SKyle Evans 	_carry = 0;
307*f0865ec9SKyle Evans 	for(i = 0; i < GOSTR34_11_94_STATE_SIZE; i++){
308*f0865ec9SKyle Evans 		u64 a, b, c;
309*f0865ec9SKyle Evans 		unsigned int idx = (GOSTR34_11_94_STATE_SIZE - i - 1);
310*f0865ec9SKyle Evans 		GET_UINT64_BE(a, (const u8*)(&A[idx]), 0);
311*f0865ec9SKyle Evans 		GET_UINT64_BE(b, (const u8*)(&B[idx]), 0);
312*f0865ec9SKyle Evans 		tmp = (u64)(a + b);
313*f0865ec9SKyle Evans 		carry1 = (u64)(tmp < a);
314*f0865ec9SKyle Evans 		c = (u64)(tmp + _carry);
315*f0865ec9SKyle Evans 		carry2 = (u64)(c < tmp);
316*f0865ec9SKyle Evans 		_carry = (u64)(carry1 | carry2);
317*f0865ec9SKyle Evans 		PUT_UINT64_BE(c, (u8*)(&C[idx]), 0);
318*f0865ec9SKyle Evans 	}
319*f0865ec9SKyle Evans 
320*f0865ec9SKyle Evans 	return;
321*f0865ec9SKyle Evans }
322*f0865ec9SKyle Evans 
323*f0865ec9SKyle Evans /* GOSTR34_11_94 core processing. Returns 0 on success, -1 on error. */
gostr34_11_94_process(gostr34_11_94_context * ctx,const u8 data[GOSTR34_11_94_BLOCK_SIZE])324*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_process(gostr34_11_94_context *ctx,
325*f0865ec9SKyle Evans 			   const u8 data[GOSTR34_11_94_BLOCK_SIZE])
326*f0865ec9SKyle Evans {
327*f0865ec9SKyle Evans 	int ret;
328*f0865ec9SKyle Evans 	unsigned int i;
329*f0865ec9SKyle Evans 	u64 K[4][GOSTR34_11_94_STATE_SIZE];
330*f0865ec9SKyle Evans 	u64 H[GOSTR34_11_94_STATE_SIZE], S[GOSTR34_11_94_STATE_SIZE], M[GOSTR34_11_94_STATE_SIZE];
331*f0865ec9SKyle Evans 
332*f0865ec9SKyle Evans 	MUST_HAVE((data != NULL), ret, err);
333*f0865ec9SKyle Evans 	GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);
334*f0865ec9SKyle Evans 	/* Get our local data in little endian format */
335*f0865ec9SKyle Evans 	for(i = 0; i < GOSTR34_11_94_BLOCK_SIZE; i++){
336*f0865ec9SKyle Evans 		((u8*)M)[i] = data[GOSTR34_11_94_BLOCK_SIZE - i - 1];
337*f0865ec9SKyle Evans 	}
338*f0865ec9SKyle Evans 	/* Get the saved state */
339*f0865ec9SKyle Evans 	for(i = 0; i < GOSTR34_11_94_BLOCK_SIZE; i++){
340*f0865ec9SKyle Evans 		((u8*)H)[i] = ((u8*)ctx->gostr34_11_94_state)[GOSTR34_11_94_BLOCK_SIZE - i - 1];
341*f0865ec9SKyle Evans 	}
342*f0865ec9SKyle Evans 
343*f0865ec9SKyle Evans 	/* Key generation */
344*f0865ec9SKyle Evans 	ret = gostr34_11_94_key_generation(H, M, K); EG(ret, err);
345*f0865ec9SKyle Evans 	/* State encryption */
346*f0865ec9SKyle Evans 	switch(ctx->gostr34_11_94_t){
347*f0865ec9SKyle Evans 		case GOST34_11_94_NORM:{
348*f0865ec9SKyle Evans 			ret = gostr34_11_94_state_encryption((const u64 (*)[4])K, H, S, gostr34_11_94_sbox_norm); EG(ret, err);
349*f0865ec9SKyle Evans 			break;
350*f0865ec9SKyle Evans 		}
351*f0865ec9SKyle Evans 		case GOST34_11_94_RFC4357:{
352*f0865ec9SKyle Evans 			ret = gostr34_11_94_state_encryption((const u64 (*)[4])K, H, S, gostr34_11_94_sbox_rfc4357); EG(ret, err);
353*f0865ec9SKyle Evans 			break;
354*f0865ec9SKyle Evans 		}
355*f0865ec9SKyle Evans 		default:{
356*f0865ec9SKyle Evans 			ret = -1;
357*f0865ec9SKyle Evans 			goto err;
358*f0865ec9SKyle Evans 		}
359*f0865ec9SKyle Evans 	}
360*f0865ec9SKyle Evans 	/* Output transformation */
361*f0865ec9SKyle Evans 	ret = gostr34_11_94_state_output_transform(H, S, M, ctx->gostr34_11_94_state); EG(ret, err);
362*f0865ec9SKyle Evans 	/* Update the internal sum */
363*f0865ec9SKyle Evans 	gostr34_11_94_256bit_sum(ctx->gostr34_11_94_sum, M, ctx->gostr34_11_94_sum);
364*f0865ec9SKyle Evans 
365*f0865ec9SKyle Evans 	ret = 0;
366*f0865ec9SKyle Evans 
367*f0865ec9SKyle Evans err:
368*f0865ec9SKyle Evans 	return ret;
369*f0865ec9SKyle Evans }
370*f0865ec9SKyle Evans 
371*f0865ec9SKyle Evans /* Init hash function. Returns 0 on success, -1 on error. */
gostr34_11_94_init(gostr34_11_94_context * ctx)372*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_init(gostr34_11_94_context *ctx)
373*f0865ec9SKyle Evans {
374*f0865ec9SKyle Evans 	int ret;
375*f0865ec9SKyle Evans 
376*f0865ec9SKyle Evans 	MUST_HAVE((ctx != NULL), ret, err);
377*f0865ec9SKyle Evans 
378*f0865ec9SKyle Evans 	/* Sanity check on size */
379*f0865ec9SKyle Evans 	MUST_HAVE((GOSTR34_11_94_DIGEST_SIZE <= MAX_DIGEST_SIZE), ret, err);
380*f0865ec9SKyle Evans 
381*f0865ec9SKyle Evans 	ctx->gostr34_11_94_total = 0;
382*f0865ec9SKyle Evans 	ctx->gostr34_11_94_state[0] = 0;
383*f0865ec9SKyle Evans 	ctx->gostr34_11_94_state[1] = 0;
384*f0865ec9SKyle Evans 	ctx->gostr34_11_94_state[2] = 0;
385*f0865ec9SKyle Evans 	ctx->gostr34_11_94_state[3] = 0;
386*f0865ec9SKyle Evans 
387*f0865ec9SKyle Evans 	ret = local_memset(ctx->gostr34_11_94_sum, 0, sizeof(ctx->gostr34_11_94_sum)); EG(ret, err);
388*f0865ec9SKyle Evans 
389*f0865ec9SKyle Evans 	/* Our default GOST34_11_94 type is GOST34_11_94_NORM */
390*f0865ec9SKyle Evans 	ctx->gostr34_11_94_t = GOST34_11_94_NORM;
391*f0865ec9SKyle Evans 
392*f0865ec9SKyle Evans 	/* Tell that we are initialized */
393*f0865ec9SKyle Evans 	ctx->magic = GOSTR34_11_94_HASH_MAGIC;
394*f0865ec9SKyle Evans 
395*f0865ec9SKyle Evans 	ret = 0;
396*f0865ec9SKyle Evans 
397*f0865ec9SKyle Evans err:
398*f0865ec9SKyle Evans 	return ret;
399*f0865ec9SKyle Evans }
400*f0865ec9SKyle Evans 
401*f0865ec9SKyle Evans /* Function to modify the initial IV as it is not imposed by the RFCs */
gostr34_11_94_set_iv(gostr34_11_94_context * ctx,const u64 iv[GOSTR34_11_94_STATE_SIZE])402*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_set_iv(gostr34_11_94_context *ctx, const u64 iv[GOSTR34_11_94_STATE_SIZE])
403*f0865ec9SKyle Evans {
404*f0865ec9SKyle Evans 	int ret;
405*f0865ec9SKyle Evans 
406*f0865ec9SKyle Evans 	MUST_HAVE((iv != NULL), ret, err);
407*f0865ec9SKyle Evans 	GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);
408*f0865ec9SKyle Evans 
409*f0865ec9SKyle Evans 	/* We cannot change the IV after the first update */
410*f0865ec9SKyle Evans 	MUST_HAVE((ctx->gostr34_11_94_total == 0), ret, err);
411*f0865ec9SKyle Evans 
412*f0865ec9SKyle Evans 	ctx->gostr34_11_94_state[0] = iv[0];
413*f0865ec9SKyle Evans 	ctx->gostr34_11_94_state[1] = iv[1];
414*f0865ec9SKyle Evans 	ctx->gostr34_11_94_state[2] = iv[2];
415*f0865ec9SKyle Evans 	ctx->gostr34_11_94_state[3] = iv[3];
416*f0865ec9SKyle Evans 
417*f0865ec9SKyle Evans 	ret = 0;
418*f0865ec9SKyle Evans 
419*f0865ec9SKyle Evans err:
420*f0865ec9SKyle Evans 	return ret;
421*f0865ec9SKyle Evans }
422*f0865ec9SKyle Evans 
423*f0865ec9SKyle Evans /* Function to modify the GOST type (that will dictate the underlying SBOX to use for block encryption) */
gostr34_11_94_set_type(gostr34_11_94_context * ctx,gostr34_11_94_type type)424*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_set_type(gostr34_11_94_context *ctx, gostr34_11_94_type type)
425*f0865ec9SKyle Evans {
426*f0865ec9SKyle Evans 	int ret;
427*f0865ec9SKyle Evans 
428*f0865ec9SKyle Evans 	GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);
429*f0865ec9SKyle Evans 
430*f0865ec9SKyle Evans 	/* We cannot change the algorithm type after the first update */
431*f0865ec9SKyle Evans 	MUST_HAVE((ctx->gostr34_11_94_total == 0), ret, err);
432*f0865ec9SKyle Evans 
433*f0865ec9SKyle Evans 	if((type != GOST34_11_94_NORM) && (type != GOST34_11_94_RFC4357)){
434*f0865ec9SKyle Evans 		ret = -1;
435*f0865ec9SKyle Evans 		goto err;
436*f0865ec9SKyle Evans 	}
437*f0865ec9SKyle Evans 
438*f0865ec9SKyle Evans 	ctx->gostr34_11_94_t = type;
439*f0865ec9SKyle Evans 
440*f0865ec9SKyle Evans 	ret = 0;
441*f0865ec9SKyle Evans 
442*f0865ec9SKyle Evans err:
443*f0865ec9SKyle Evans 	return ret;
444*f0865ec9SKyle Evans }
445*f0865ec9SKyle Evans 
446*f0865ec9SKyle Evans 
gostr34_11_94_update(gostr34_11_94_context * ctx,const u8 * input,u32 ilen)447*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_update(gostr34_11_94_context *ctx, const u8 *input, u32 ilen)
448*f0865ec9SKyle Evans {
449*f0865ec9SKyle Evans 	const u8 *data_ptr = input;
450*f0865ec9SKyle Evans 	u32 remain_ilen = ilen;
451*f0865ec9SKyle Evans 	u16 fill;
452*f0865ec9SKyle Evans 	u8 left;
453*f0865ec9SKyle Evans 	int ret;
454*f0865ec9SKyle Evans 
455*f0865ec9SKyle Evans 	MUST_HAVE((input != NULL) || (ilen == 0), ret, err);
456*f0865ec9SKyle Evans 	GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);
457*f0865ec9SKyle Evans 
458*f0865ec9SKyle Evans 	/* Nothing to process, return */
459*f0865ec9SKyle Evans 	if (ilen == 0) {
460*f0865ec9SKyle Evans 		ret = 0;
461*f0865ec9SKyle Evans 		goto err;
462*f0865ec9SKyle Evans 	}
463*f0865ec9SKyle Evans 
464*f0865ec9SKyle Evans 	/* Get what's left in our local buffer */
465*f0865ec9SKyle Evans 	left = (ctx->gostr34_11_94_total & 0x3F);
466*f0865ec9SKyle Evans 	fill = (u16)(GOSTR34_11_94_BLOCK_SIZE - left);
467*f0865ec9SKyle Evans 
468*f0865ec9SKyle Evans 	ctx->gostr34_11_94_total += ilen;
469*f0865ec9SKyle Evans 
470*f0865ec9SKyle Evans 	if ((left > 0) && (remain_ilen >= fill)) {
471*f0865ec9SKyle Evans 		/* Copy data at the end of the buffer */
472*f0865ec9SKyle Evans 		ret = local_memcpy(ctx->gostr34_11_94_buffer + left, data_ptr, fill); EG(ret, err);
473*f0865ec9SKyle Evans 		ret = gostr34_11_94_process(ctx, ctx->gostr34_11_94_buffer); EG(ret, err);
474*f0865ec9SKyle Evans 		data_ptr += fill;
475*f0865ec9SKyle Evans 		remain_ilen -= fill;
476*f0865ec9SKyle Evans 		left = 0;
477*f0865ec9SKyle Evans 	}
478*f0865ec9SKyle Evans 
479*f0865ec9SKyle Evans 	while (remain_ilen >= GOSTR34_11_94_BLOCK_SIZE) {
480*f0865ec9SKyle Evans 		ret = gostr34_11_94_process(ctx, data_ptr); EG(ret, err);
481*f0865ec9SKyle Evans 		data_ptr += GOSTR34_11_94_BLOCK_SIZE;
482*f0865ec9SKyle Evans 		remain_ilen -= GOSTR34_11_94_BLOCK_SIZE;
483*f0865ec9SKyle Evans 	}
484*f0865ec9SKyle Evans 
485*f0865ec9SKyle Evans 	if (remain_ilen > 0) {
486*f0865ec9SKyle Evans 		ret = local_memcpy(ctx->gostr34_11_94_buffer + left, data_ptr, remain_ilen); EG(ret, err);
487*f0865ec9SKyle Evans 	}
488*f0865ec9SKyle Evans 
489*f0865ec9SKyle Evans 	ret = 0;
490*f0865ec9SKyle Evans 
491*f0865ec9SKyle Evans err:
492*f0865ec9SKyle Evans 	return ret;
493*f0865ec9SKyle Evans }
494*f0865ec9SKyle Evans 
495*f0865ec9SKyle Evans /* Finalize. Returns 0 on success, -1 on error.*/
gostr34_11_94_final(gostr34_11_94_context * ctx,u8 output[GOSTR34_11_94_DIGEST_SIZE])496*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_final(gostr34_11_94_context *ctx, u8 output[GOSTR34_11_94_DIGEST_SIZE])
497*f0865ec9SKyle Evans {
498*f0865ec9SKyle Evans 	unsigned int block_present = 0;
499*f0865ec9SKyle Evans 	u8 last_padded_block[2 * GOSTR34_11_94_BLOCK_SIZE];
500*f0865ec9SKyle Evans 	int ret;
501*f0865ec9SKyle Evans 
502*f0865ec9SKyle Evans 	MUST_HAVE((output != NULL), ret, err);
503*f0865ec9SKyle Evans 	GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);
504*f0865ec9SKyle Evans 
505*f0865ec9SKyle Evans 	/* This is our final step, so we proceed with the padding if necessary */
506*f0865ec9SKyle Evans 	/* Fill in our last block with zeroes */
507*f0865ec9SKyle Evans 	ret = local_memset(last_padded_block, 0, sizeof(last_padded_block)); EG(ret, err);
508*f0865ec9SKyle Evans 
509*f0865ec9SKyle Evans 	block_present = ctx->gostr34_11_94_total % GOSTR34_11_94_BLOCK_SIZE;
510*f0865ec9SKyle Evans 	/* Copy what's left in our temporary context buffer */
511*f0865ec9SKyle Evans 	ret = local_memcpy(last_padded_block, ctx->gostr34_11_94_buffer,
512*f0865ec9SKyle Evans 			     block_present); EG(ret, err);
513*f0865ec9SKyle Evans 
514*f0865ec9SKyle Evans 	/* Put in the second block the size in bits of the message in bits in little endian */
515*f0865ec9SKyle Evans 	PUT_UINT64_LE(8 * ctx->gostr34_11_94_total, last_padded_block, GOSTR34_11_94_BLOCK_SIZE);
516*f0865ec9SKyle Evans 
517*f0865ec9SKyle Evans 	if(block_present != 0){
518*f0865ec9SKyle Evans 		/* Process padding block if necessary */
519*f0865ec9SKyle Evans 		ret = gostr34_11_94_process(ctx, last_padded_block); EG(ret, err);
520*f0865ec9SKyle Evans 	}
521*f0865ec9SKyle Evans 	/* Copy our sum in the beginning of the block */
522*f0865ec9SKyle Evans 	if(gostr34_11_94_arch_is_big_endian()){
523*f0865ec9SKyle Evans 		PUT_UINT64_LE(ctx->gostr34_11_94_sum[3], last_padded_block, 0);
524*f0865ec9SKyle Evans 		PUT_UINT64_LE(ctx->gostr34_11_94_sum[2], last_padded_block, 8);
525*f0865ec9SKyle Evans 		PUT_UINT64_LE(ctx->gostr34_11_94_sum[1], last_padded_block, 16);
526*f0865ec9SKyle Evans 		PUT_UINT64_LE(ctx->gostr34_11_94_sum[0], last_padded_block, 24);
527*f0865ec9SKyle Evans 	}
528*f0865ec9SKyle Evans 	else{
529*f0865ec9SKyle Evans 		PUT_UINT64_BE(ctx->gostr34_11_94_sum[3], last_padded_block, 0);
530*f0865ec9SKyle Evans 		PUT_UINT64_BE(ctx->gostr34_11_94_sum[2], last_padded_block, 8);
531*f0865ec9SKyle Evans 		PUT_UINT64_BE(ctx->gostr34_11_94_sum[1], last_padded_block, 16);
532*f0865ec9SKyle Evans 		PUT_UINT64_BE(ctx->gostr34_11_94_sum[0], last_padded_block, 24);
533*f0865ec9SKyle Evans 	}
534*f0865ec9SKyle Evans 
535*f0865ec9SKyle Evans 	/* Process the "size" in bits block */
536*f0865ec9SKyle Evans 	ret = gostr34_11_94_process(ctx, last_padded_block + GOSTR34_11_94_BLOCK_SIZE); EG(ret, err);
537*f0865ec9SKyle Evans 	/* Process the message blocks sum */
538*f0865ec9SKyle Evans 	ret = gostr34_11_94_process(ctx, last_padded_block); EG(ret, err);
539*f0865ec9SKyle Evans 
540*f0865ec9SKyle Evans 	/* Output the hash result */
541*f0865ec9SKyle Evans 	if(gostr34_11_94_arch_is_big_endian()){
542*f0865ec9SKyle Evans 		PUT_UINT64_BE(ctx->gostr34_11_94_state[0], output, 0);
543*f0865ec9SKyle Evans 		PUT_UINT64_BE(ctx->gostr34_11_94_state[1], output, 8);
544*f0865ec9SKyle Evans 		PUT_UINT64_BE(ctx->gostr34_11_94_state[2], output, 16);
545*f0865ec9SKyle Evans 		PUT_UINT64_BE(ctx->gostr34_11_94_state[3], output, 24);
546*f0865ec9SKyle Evans 	}
547*f0865ec9SKyle Evans 	else{
548*f0865ec9SKyle Evans 		PUT_UINT64_LE(ctx->gostr34_11_94_state[0], output, 0);
549*f0865ec9SKyle Evans 		PUT_UINT64_LE(ctx->gostr34_11_94_state[1], output, 8);
550*f0865ec9SKyle Evans 		PUT_UINT64_LE(ctx->gostr34_11_94_state[2], output, 16);
551*f0865ec9SKyle Evans 		PUT_UINT64_LE(ctx->gostr34_11_94_state[3], output, 24);
552*f0865ec9SKyle Evans 	}
553*f0865ec9SKyle Evans 
554*f0865ec9SKyle Evans 	/* Tell that we are uninitialized */
555*f0865ec9SKyle Evans 	ctx->magic = WORD(0);
556*f0865ec9SKyle Evans 
557*f0865ec9SKyle Evans 	ret = 0;
558*f0865ec9SKyle Evans 
559*f0865ec9SKyle Evans err:
560*f0865ec9SKyle Evans 	return ret;
561*f0865ec9SKyle Evans }
562*f0865ec9SKyle Evans 
563*f0865ec9SKyle Evans 
564*f0865ec9SKyle Evans /*
565*f0865ec9SKyle Evans  * Scattered version performing init/update/finalize on a vector of buffers
566*f0865ec9SKyle Evans  * 'inputs' with the length of each buffer passed via 'ilens'. The function
567*f0865ec9SKyle Evans  * loops on pointers in 'inputs' until it finds a NULL pointer. The function
568*f0865ec9SKyle Evans  * returns 0 on success, -1 on error.
569*f0865ec9SKyle Evans  */
gostr34_11_94_scattered(const u8 ** inputs,const u32 * ilens,u8 output[GOSTR34_11_94_DIGEST_SIZE],gostr34_11_94_type type)570*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_scattered(const u8 **inputs, const u32 *ilens,
571*f0865ec9SKyle Evans 		      u8 output[GOSTR34_11_94_DIGEST_SIZE], gostr34_11_94_type type)
572*f0865ec9SKyle Evans {
573*f0865ec9SKyle Evans 	gostr34_11_94_context ctx;
574*f0865ec9SKyle Evans 	int ret, pos = 0;
575*f0865ec9SKyle Evans 
576*f0865ec9SKyle Evans 	MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
577*f0865ec9SKyle Evans 
578*f0865ec9SKyle Evans 	ret = gostr34_11_94_init(&ctx); EG(ret, err);
579*f0865ec9SKyle Evans 	ret = gostr34_11_94_set_type(&ctx, type); EG(ret, err);
580*f0865ec9SKyle Evans 
581*f0865ec9SKyle Evans 	while (inputs[pos] != NULL) {
582*f0865ec9SKyle Evans 		ret = gostr34_11_94_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);
583*f0865ec9SKyle Evans 		pos += 1;
584*f0865ec9SKyle Evans 	}
585*f0865ec9SKyle Evans 
586*f0865ec9SKyle Evans 	ret = gostr34_11_94_final(&ctx, output);
587*f0865ec9SKyle Evans 
588*f0865ec9SKyle Evans err:
589*f0865ec9SKyle Evans 	return ret;
590*f0865ec9SKyle Evans }
591*f0865ec9SKyle Evans 
gostr34_11_94_scattered_norm(const u8 ** inputs,const u32 * ilens,u8 output[GOSTR34_11_94_DIGEST_SIZE])592*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_scattered_norm(const u8 **inputs, const u32 *ilens,
593*f0865ec9SKyle Evans 		      u8 output[GOSTR34_11_94_DIGEST_SIZE])
594*f0865ec9SKyle Evans {
595*f0865ec9SKyle Evans 	return gostr34_11_94_scattered(inputs, ilens, output, GOST34_11_94_NORM);
596*f0865ec9SKyle Evans }
597*f0865ec9SKyle Evans 
gostr34_11_94_scattered_rfc4357(const u8 ** inputs,const u32 * ilens,u8 output[GOSTR34_11_94_DIGEST_SIZE])598*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_scattered_rfc4357(const u8 **inputs, const u32 *ilens,
599*f0865ec9SKyle Evans 		      u8 output[GOSTR34_11_94_DIGEST_SIZE])
600*f0865ec9SKyle Evans {
601*f0865ec9SKyle Evans 	return gostr34_11_94_scattered(inputs, ilens, output, GOST34_11_94_RFC4357);
602*f0865ec9SKyle Evans }
603*f0865ec9SKyle Evans 
604*f0865ec9SKyle Evans 
605*f0865ec9SKyle Evans /*
606*f0865ec9SKyle Evans  * Single call version performing init/update/final on given input.
607*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
608*f0865ec9SKyle Evans  */
gostr34_11_94(const u8 * input,u32 ilen,u8 output[GOSTR34_11_94_DIGEST_SIZE],gostr34_11_94_type type)609*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94(const u8 *input, u32 ilen, u8 output[GOSTR34_11_94_DIGEST_SIZE], gostr34_11_94_type type)
610*f0865ec9SKyle Evans {
611*f0865ec9SKyle Evans 	gostr34_11_94_context ctx;
612*f0865ec9SKyle Evans 	int ret;
613*f0865ec9SKyle Evans 
614*f0865ec9SKyle Evans 	ret = gostr34_11_94_init(&ctx); EG(ret, err);
615*f0865ec9SKyle Evans 	ret = gostr34_11_94_set_type(&ctx, type); EG(ret, err);
616*f0865ec9SKyle Evans 	ret = gostr34_11_94_update(&ctx, input, ilen); EG(ret, err);
617*f0865ec9SKyle Evans 	ret = gostr34_11_94_final(&ctx, output);
618*f0865ec9SKyle Evans 
619*f0865ec9SKyle Evans err:
620*f0865ec9SKyle Evans 	return ret;
621*f0865ec9SKyle Evans }
622*f0865ec9SKyle Evans 
gostr34_11_94_norm(const u8 * input,u32 ilen,u8 output[GOSTR34_11_94_DIGEST_SIZE])623*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_norm(const u8 *input, u32 ilen, u8 output[GOSTR34_11_94_DIGEST_SIZE])
624*f0865ec9SKyle Evans {
625*f0865ec9SKyle Evans 	return gostr34_11_94(input, ilen, output, GOST34_11_94_NORM);
626*f0865ec9SKyle Evans }
627*f0865ec9SKyle Evans 
gostr34_11_94_rfc4357(const u8 * input,u32 ilen,u8 output[GOSTR34_11_94_DIGEST_SIZE])628*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_rfc4357(const u8 *input, u32 ilen, u8 output[GOSTR34_11_94_DIGEST_SIZE])
629*f0865ec9SKyle Evans {
630*f0865ec9SKyle Evans 	return gostr34_11_94(input, ilen, output, GOST34_11_94_RFC4357);
631*f0865ec9SKyle Evans }
632