xref: /freebsd/crypto/libecc/src/hash/shake.c (revision 0e8011faf58b743cc652e3b2ad0f7671227610df)
1 /*
2  *  Copyright (C) 2021 - 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 #include <libecc/utils/utils.h>
12 #include <libecc/hash/shake.h>
13 
14 /* Init function depending on the digest size */
15 int _shake_init(shake_context *ctx, u8 digest_size, u8 block_size)
16 {
17 	int ret;
18 
19 	MUST_HAVE((ctx != NULL), ret, err);
20 
21         /* Zeroize the internal state */
22         ret = local_memset(ctx->shake_state, 0, sizeof(ctx->shake_state)); EG(ret, err);
23 
24         ctx->shake_idx = 0;
25         ctx->shake_digest_size = digest_size;
26         ctx->shake_block_size = block_size;
27 
28 	/* Detect endianness */
29 	ctx->shake_endian = arch_is_big_endian() ? SHAKE_BIG : SHAKE_LITTLE;
30 
31 err:
32         return ret;
33 }
34 
35 /* Update hash function */
36 int _shake_update(shake_context *ctx, const u8 *input, u32 ilen)
37 {
38         u32 i;
39         u8 *state;
40 	int ret;
41 
42         MUST_HAVE((ctx != NULL) && ((input != NULL) || (ilen == 0)), ret, err);
43 
44         state = (u8*)(ctx->shake_state);
45 
46         for(i = 0; i < ilen; i++){
47                 /* Compute the index depending on the endianness */
48 		u64 idx = (ctx->shake_endian == SHAKE_LITTLE) ? ctx->shake_idx : SWAP64_Idx(ctx->shake_idx);
49                 ctx->shake_idx++;
50                 /* Update the state, and adapt endianness order */
51                 state[idx] ^= input[i];
52                 if(ctx->shake_idx == ctx->shake_block_size){
53                         KECCAKF(ctx->shake_state);
54                         ctx->shake_idx = 0;
55                 }
56         }
57 	ret = 0;
58 
59 err:
60         return ret;
61 }
62 
63 /* Finalize hash function */
64 int _shake_finalize(shake_context *ctx, u8 *output)
65 {
66         unsigned int i;
67         u8 *state;
68 	int ret;
69 
70         MUST_HAVE((ctx != NULL) && (output != NULL), ret, err);
71         MUST_HAVE((ctx->shake_digest_size <= sizeof(ctx->shake_state)), ret, err);
72 
73         state = (u8*)(ctx->shake_state);
74 
75         /* Proceed with the padding of the last block */
76         /* Compute the index depending on the endianness */
77         if(ctx->shake_endian == SHAKE_LITTLE){
78                 /* Little endian case */
79                 state[ctx->shake_idx] ^= 0x1f;
80                 state[ctx->shake_block_size - 1] ^= 0x80;
81         }
82         else{
83                 /* Big endian case */
84                 state[SWAP64_Idx(ctx->shake_idx)] ^= 0x1f;
85                 state[SWAP64_Idx(ctx->shake_block_size - 1)] ^= 0x80;
86         }
87 	/* Produce the output.
88 	 * NOTE: we should have a fixed version of SHAKE producing an output size
89 	 * with size less than the state size.
90 	 */
91 	KECCAKF(ctx->shake_state);
92         for(i = 0; i < ctx->shake_digest_size; i++){
93                 output[i] = (ctx->shake_endian == SHAKE_LITTLE) ? state[i] : state[SWAP64_Idx(i)];
94 	}
95 
96         /* Uninit our context magic */
97         ctx->magic = WORD(0);
98 
99         ret = 0;
100 
101 err:
102         return ret;
103 }
104