parallel_hash.c
Go to the documentation of this file.
1 /**
2  * @file parallel_hash.c
3  * @brief ParallelHash hash function
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * The purpose of ParallelHash1 is to support the efficient hashing of very
30  * long strings, by taking advantage of the parallelism available in modern
31  * processors. ParallelHash supports the 128- and 256-bit security strengths
32  *
33  * @author Oryx Embedded SARL (www.oryx-embedded.com)
34  * @version 2.6.6
35  **/
36 
37 //Switch to the appropriate trace level
38 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
39 
40 //Dependencies
41 #include "core/crypto.h"
42 #include "hash/parallel_hash.h"
43 
44 //Check crypto library configuration
45 #if (PARALLEL_HASH_SUPPORT == ENABLED)
46 
47 
48 /**
49  * @brief Digest a message using ParallelHash
50  * @param[in] strength Number of bits of security (128 for ParallelHash128 and
51  * 256 for ParallelHash256)
52  * @param[in] blockSize Block size in bytes for parallel hashing (B)
53  * @param[in] data Pointer to the input string (X)
54  * @param[in] dataLen Length of the input string
55  * @param[in] custom Customization string (S)
56  * @param[in] customLen Length of the customization string
57  * @param[out] digest Calculated digest
58  * @param[in] digestLen Expected length of the digest (L)
59  * @return Error code
60  **/
61 
62 error_t parallelHashCompute(uint_t strength, size_t blockSize,
63  const void *data, size_t dataLen, const char_t *custom, size_t customLen,
64  uint8_t *digest, size_t digestLen)
65 {
66  error_t error;
67 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
68  ParallelHashContext *context;
69 #else
70  ParallelHashContext context[1];
71 #endif
72 
73  //Check parameters
74  if(data == NULL && dataLen != 0)
76 
77  if(digest == NULL && digestLen != 0)
79 
80 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
81  //Allocate a memory buffer to hold the ParallelHash context
82  context = cryptoAllocMem(sizeof(ParallelHashContext));
83  //Failed to allocate memory?
84  if(context == NULL)
85  return ERROR_OUT_OF_MEMORY;
86 #endif
87 
88  //Initialize the ParallelHash context
89  error = parallelHashInit(context, strength, blockSize, custom, customLen);
90 
91  //Check status code
92  if(!error)
93  {
94  //Digest the input string
95  parallelHashUpdate(context, data, dataLen);
96  //Finalize the ParallelHash computation
97  parallelHashFinal(context, digest, digestLen);
98  }
99 
100 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
101  //Free previously allocated memory
102  cryptoFreeMem(context);
103 #endif
104 
105  //Return status code
106  return error;
107 }
108 
109 
110 /**
111  * @brief Initialize ParallelHash message digest context
112  * @param[in] context Pointer to the ParallelHash context to initialize
113  * @param[in] strength Number of bits of security (128 for ParallelHash128 and
114  * 256 for ParallelHash256)
115  * @param[in] blockSize Block size in bytes for parallel hashing (B)
116  * @param[in] custom Customization string (S)
117  * @param[in] customLen Length of the customization string
118  * @return Error code
119  **/
120 
122  size_t blockSize, const char_t *custom, size_t customLen)
123 {
124  error_t error;
125  size_t n;
126  uint8_t buffer[sizeof(size_t) + 1];
127 
128  //Make sure the ParallelHash context is valid
129  if(context == NULL)
131 
132  //Check block size
133  if(blockSize == 0)
135 
136  //Initialize parameters
137  context->strength = strength;
138  context->blockSize = blockSize;
139  context->blockPos = 0;
140  context->blockCount = 0;
141 
142  //The length of the hash values depends on the ParallelHash variant
143  context->hLen = (strength == 128) ? 32 : 64;
144 
145  //Initialize the first cSHAKE instance
146  error = cshakeInit(&context->cshakeContext1, strength, "", 0, "", 0);
147 
148  //Check status code
149  if(!error)
150  {
151  //Initialize the second cSHAKE instance
152  error = cshakeInit(&context->cshakeContext2, strength, "ParallelHash",
153  12, custom, customLen);
154  }
155 
156  //Check status code
157  if(!error)
158  {
159  //Absorb the string representation of B
160  cshakeLeftEncode(blockSize, buffer, &n);
161  cshakeAbsorb(&context->cshakeContext2, buffer, n);
162  }
163 
164  //Return status code
165  return error;
166 }
167 
168 
169 /**
170  * @brief Update the ParallelHash context with a portion of the message being hashed
171  * @param[in] context Pointer to the ParallelHash context
172  * @param[in] data Pointer to the input string
173  * @param[in] length Length of the string
174  **/
175 
176 void parallelHashUpdate(ParallelHashContext *context, const void *data, size_t length)
177 {
178  size_t n;
179  uint8_t h[64];
180 
181  //Process the input string
182  while(length > 0)
183  {
184  //Limit the number of bytes to process at a time
185  n = MIN(context->blockSize - context->blockPos, length);
186 
187  //Absorb the input data
188  cshakeAbsorb(&context->cshakeContext1, data, n);
189  context->blockPos += n;
190 
191  //ParallelHash operates in a block-by-block fashion
192  if(context->blockPos == context->blockSize)
193  {
194  //Compute the hash value for each block separately
195  cshakeFinal(&context->cshakeContext1);
196  cshakeSqueeze(&context->cshakeContext1, h, context->hLen);
197 
198  //The resulting hash values are combined and passed to cSHAKE
199  cshakeAbsorb(&context->cshakeContext2, h, context->hLen);
200 
201  //Re-initialize the cSHAKE context
202  cshakeInit(&context->cshakeContext1, context->strength, "", 0, "", 0);
203 
204  //The block is empty
205  context->blockPos = 0;
206  //Increment the number of blocks
207  context->blockCount++;
208  }
209 
210  //Advance the data pointer
211  data = (uint8_t *) data + n;
212  //Remaining bytes to process
213  length -= n;
214  }
215 }
216 
217 
218 /**
219  * @brief Finish the ParallelHash message digest
220  * @param[in] context Pointer to the ParallelHash context
221  * @param[out] digest Calculated digest
222  * @param[in] length Expected length of the digest (L)
223  **/
224 
225 void parallelHashFinal(ParallelHashContext *context, uint8_t *digest, size_t length)
226 {
227  size_t n;
228  uint8_t buffer[sizeof(size_t) + 1];
229 
230  //Absorb the string representation of n
231  cshakeRightEncode(context->blockCount, buffer, &n);
232  cshakeAbsorb(&context->cshakeContext2, buffer, n);
233 
234  //Absorb the string representation of L
235  cshakeRightEncode(length * 8, buffer, &n);
236  cshakeAbsorb(&context->cshakeContext2, buffer, n);
237 
238  //Finish absorbing phase
239  cshakeFinal(&context->cshakeContext2);
240  //Extract data from the squeezing phase
241  cshakeSqueeze(&context->cshakeContext2, digest, length);
242 }
243 
244 #endif
error_t cshakeInit(CshakeContext *context, uint_t strength, const char_t *name, size_t nameLen, const char_t *custom, size_t customLen)
Initialize cSHAKE context.
Definition: cshake.c:124
uint8_t data[]
Definition: ethernet.h:224
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
ParallelHash hash function.
uint8_t h
Definition: ndp.h:302
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t
Error codes.
Definition: error.h:43
void cshakeFinal(CshakeContext *context)
Finish absorbing phase.
Definition: cshake.c:220
General definitions for cryptographic algorithms.
uint8_t length
Definition: tcp.h:375
void parallelHashUpdate(ParallelHashContext *context, const void *data, size_t length)
Update the ParallelHash context with a portion of the message being hashed.
#define MIN(a, b)
Definition: os_port.h:63
void cshakeAbsorb(CshakeContext *context, const void *input, size_t length)
Absorb data.
Definition: cshake.c:208
error_t parallelHashCompute(uint_t strength, size_t blockSize, const void *data, size_t dataLen, const char_t *custom, size_t customLen, uint8_t *digest, size_t digestLen)
Digest a message using ParallelHash.
Definition: parallel_hash.c:62
uint32_t dataLen
Definition: sftp_common.h:229
void cshakeLeftEncode(size_t value, uint8_t *buffer, size_t *length)
Encode integer as byte string.
Definition: cshake.c:262
char char_t
Definition: compiler_port.h:55
error_t parallelHashInit(ParallelHashContext *context, uint_t strength, size_t blockSize, const char_t *custom, size_t customLen)
Initialize ParallelHash message digest context.
void parallelHashFinal(ParallelHashContext *context, uint8_t *digest, size_t length)
Finish the ParallelHash message digest.
uint8_t n
CshakeContext cshakeContext2
Definition: parallel_hash.h:61
#define cryptoFreeMem(p)
Definition: crypto.h:966
#define cryptoAllocMem(size)
Definition: crypto.h:961
void cshakeRightEncode(size_t value, uint8_t *buffer, size_t *length)
Encode integer as byte string.
Definition: cshake.c:298
unsigned int uint_t
Definition: compiler_port.h:57
ParallelHash algorithm context.
Definition: parallel_hash.h:54
CshakeContext cshakeContext1
Definition: parallel_hash.h:60
void cshakeSqueeze(CshakeContext *context, uint8_t *output, size_t length)
Extract data from the squeezing phase.
Definition: cshake.c:248