/***************************************************************************
 *
 *   SPDX-License-Identifier: BSD-3-Clause
 *   Copyright(c) 2007-2026 Intel Corporation
 * 
 *   These contents may have been developed with support from one or more
 *   Intel-operated generative artificial intelligence solutions.
 *
 ***************************************************************************/

/**
 *****************************************************************************
 * @file lac_sym_hash.h
 *
 * @defgroup  LacHash  Hash
 *
 * @ingroup LacSym
 *
 * API functions of the Hash component
 *
 * @lld_start
 * @lld_overview
 * There is a single \ref cpaCySym "Symmetric LAC API" for hash, cipher,
 * auth encryption and algorithm chaining. This API is implemented by the
 * \ref LacSym "Symmetric" module. It demultiplexes calls to this API into
 * their basic operation and does some common parameter checking and deals
 * with accesses to the session table.
 *
 * The hash component supports hashing in 3 modes. PLAIN, AUTH and NESTED.
 * Plain mode is used to provide data integrity while auth mode is used to
 * provide integrity as well as its authenticity. Nested mode is intended
 * for use by non standard HMAC like algorithms such as for the SSL master
 * key secret. Partial packets is supported for both plain and auth modes.
 * In-place and out-of-place processing is supported for all modes. The
 * verify operation is supported for PLAIN and AUTH modes only.
 *
 * The hash component is responsible for implementing the hash specific
 * functionality for initialising a session and for a perform operation.
 * Statistics are maintained in the symmetric \ref CpaCySymStats64 "stats"
 * structure. This module has been separated out into two. The hash QAT module
 * deals entirely with QAT data structures. The hash module itself has minimal
 * exposure to the QAT data structures.
 *
 * @lld_dependencies
 * - \ref LacCommon
 * - \ref LacSymQat "Symmetric QAT": Hash uses the lookup table provided by
 *   this module to validate user input. Hash also uses this module to build
 *   the hash QAT request message, request param structure, populate the
 *   content descriptor, allocate and populate the hash state prefix buffer.
 *   Hash also registers its function to process the QAT response with this
 *   module.
 * - OSAL : For memory functions, atomics and locking
 *
 * @lld_module_algorithms
 * <b>a. HMAC Precomputes</b>\n
 * HMAC algorithm is specified as follows:
 * \f$ HMAC(msg) = hash((key \oplus opad) \parallel
 * hash((key \oplus ipad) \parallel msg ))\f$.
 * The key is fixed per session, and is padded up to the block size of the
 * algorithm if necessary and xored with the ipad/opad. The following portion
 * of the operation can be precomputed: \f$ hash(key \oplus ipad) \f$ as the
 * output of this intermediate hash will be the same for every perform
 * operation. This intermediate state is the intermediate state of a partial
 * partial packet. It is used as the initialiser state to \f$ hash(msg) \f$.
 * The same applies to \f$ hash(key \oplus ipad) \f$. There is a saving in
 * the data path by the length of time it takes to do two hashes on a block
 * size of data. Note: a partial packet operation generates an intermediate
 * state. The final operation on a partial packet or when a full packet is
 * used applies padding and gives the final hash result. Essentially for the
 * inner hash, a partial packet final is issued on the data, using the
 * precomputed intermediate state and returns the digest.
 *
 * For the HMAC precomputes, \ref LacSymHash_HmacPreCompute(), there are two
 * hash operations done using a internal content descriptor to configure the
 * QAT. A first partial packet is specified as the packet type for the
 * pre-computes as we need the state that uses the initialiser constants
 * specific to the algorithm. The resulting output is copied from the hash
 * state prefix buffer into the QAT content descriptor for the session being
 * initialised. The state is used each perform operation as the initialiser
 * to the algorithm
 *
 * <b>b. AES XCBC Precomputes</b>\n
 * A similar technique to HMAC will be used to generate the precomputes for
 * AES XCBC. In this case a cipher operation will be used to generate the
 * precomputed result. The Pre-compute operation involves deriving 3 128-bit
 *  keys (K1, K2 and K3) from the 128-bit secret key K.
 *
 * - K1 = 0x01010101010101010101010101010101 encrypted with Key K
 * - K2 = 0x02020202020202020202020202020202 encrypted with Key K
 * - K3 = 0x03030303030303030303030303030303 encrypted with Key K
 *
 * A content descriptor  is created with the cipher algorithm set to AES
 * in ECB mode and with the keysize set to 128 bits. The 3 constants, 16 bytes
 * each, are copied into the src buffer and an in-place cipher operation is
 * performed on the 48 bytes. ECB mode does not maintain the state, therefore
 * the 3 keys can be encrypted in one perform. The encrypted result is used by
 * the state2 field in the hash setup block of the content descriptor.
 *
 * The precompute operations use a different lac command ID and thus have a
 * different route in the response path to the symmetric code. In this
 * precompute callback function the output of the precompute operation is
 * copied into the content descriptor for the session being registered.
 *
 * <b>c. AES CCM Precomputes</b>\n
 * The precomputes for AES CCM are trivial, i.e. there is no need to perform
 * a cipher or a digest operation.  Instead, the key is stored directly in
 * the state2 field.
 *
 * <b>d. AES GCM Precomputes</b>\n
 * As with AES XCBC precomputes, a cipher operation will be used to generate
 * the precomputed result for AES GCM.  In this case the Galois Hash
 * Multiplier (H) must be derived and stored in the state2 field.  H is
 * derived by encrypting a 16-byte block of zeroes with the
 * cipher/authentication key, using AES in ECB mode.
 *
 * <b>Key size for Auth algorithms</b>\n
 * <i>Min Size</i>\n
 * RFC 2104 states "The key for HMAC can be of any length. However, less than
 *  L bytes is strongly discouraged as it would decrease the security strength
 *  of the function."
 *
 * FIPS 198a states "The size of the key, K, shall be equal to or greater than
 * L/2, where L is the size of the hash function output."
 *
 * RFC 4434 states "If the key has fewer than 128 bits, lengthen it to exactly
 * 128 bits by padding it on the right with zero bits.
 *
 * A key length of 0 upwards is accepted. It is up to the client to pass in a
 * key that complies with the standard they wish to support.
 *
 * <i>Max Size</i>\n
 * RFC 2104 section 2 states : "Applications that use keys longer than B bytes
 * will first hash the key using H and then use the resultant L byte string
 * as the actual key to HMAC
 *
 * RFC 4434 section 2 states:
 * "If the key is 129 bits or longer, shorten it to exactly 128 bits
 *  by performing the steps in AES-XCBC-PRF-128 (that is, the
 *  algorithm described in this document).  In that re-application of
 *  this algorithm, the key is 128 zero bits; the message is the
 *  too-long current key."
 *
 * We push this up to the client. They need to do the hash operation through
 * the LAC API if the key is greater than the block size of the algorithm. This
 * will reduce the key size to the digest size of the algorithm.
 *
 * RFC 3566 section 4 states:
 * AES-XCBC-MAC-96 is a secret key algorithm.  For use with either ESP or
 * AH a fixed key length of 128-bits MUST be supported.  Key lengths
 * other than 128-bits MUST NOT be supported (i.e., only 128-bit keys are
 * to be used by AES-XCBC-MAC-96).
 *
 * In this case it is up to the client to provide a key that complies with
 * the standards. i.e. exactly 128 bits in size.
 *
 *
 * <b>HMAC-MD5-96 and HMAC-SHA1-96</b>\n
 * HMAC-MD5-96 and HMAC-SHA1-96 are defined as requirements by Look Aside
 * IPsec. The differences between HMAC-SHA1 and HMAC-SHA1-96 are that the
 * digest produced is truncated and there are strict requirements on the
 * size of the key that is used.
 *
 * They are supported in LAC by HMAC-MD5 and HMAC-SHA1. The field
 * \ref CpaCySymHashSetupData::digestResultLenInBytes in the LAC API in
 * bytes needs to be set to 12 bytes. There are also requirements regarding
 * the keysize. It is up to the client to ensure the key size meets the
 * requirements of the standards they are using.
 *
 * RFC 2403: HMAC-MD5-96 Key lengths other than 128-bits MUST NOT be supported.
 * HMAC-MD5-96 produces a 128-bit authenticator value. For use with either
 * ESP or AH, a truncated value using the first 96 bits MUST be supported.
 *
 * RFC2404: HMAC-SHA1-96 Key lengths other than 160- bits MUST NOT be supported
 * HMAC-SHA-1-96 produces a 160-bit authenticator value. For use with either
 * ESP or AH, a truncated value using the first 96 bits MUST be supported.
 *
 * <b>Out of place operations</b>
 * When verify is disabled, the digest will be written to the destination
 * buffer. When verify is enabled, the digest calculated is compared to the
 * digest stored in the source buffer.
 *
 * <b>Partial Packets</b>
 * Partial packets are handled in the \ref LacSym "Symmetric" component for
 * the request. The hash callback function handles the update of the state
 * in the callback.
 *
 *
 * @lld_process_context
 *
 * Session Register Sequence Diagram: For hash modes plain and nested.
 * \msc
 *  APP [label="Application"], SYM [label="Symmetric LAC"],
 *  Achain [label="Alg chain"], Hash, SQAT [label="Symmetric QAT"];
 *
 *  APP=>SYM [ label = "cpaCySymInitSession(cbFunc)",
 *             URL="\ref cpaCySymInitSession()"] ;
 *  SYM=>SYM [ label = "LacSymSession_ParamCheck()",
 *             URL="\ref LacSymSession_ParamCheck()"];
 *  SYM=>Achain [ label = "LacAlgChain_SessionInit()",
 *                URL="\ref LacAlgChain_SessionInit()"];
 *  Achain=>Hash [ label = "LacHash_HashContextCheck()",
 *               URL="\ref LacHash_HashContextCheck()"];
 *  Achain<<Hash [ label="return"];
 *  Achain=>SQAT [ label = "LacSymQat_HashContentDescInit()",
 *               URL="\ref LacSymQat_HashContentDescInit()"];
 *  Achain<<SQAT [ label="return"];
 *  Achain=>Hash [ label = "LacHash_StatePrefixAadBufferInit()",
 *               URL="\ref LacHash_StatePrefixAadBufferInit()"];
 *  Hash=>SQAT [ label = "LacSymQat_HashStatePrefixAadBufferSizeGet()",
 *               URL="\ref LacSymQat_HashStatePrefixAadBufferSizeGet()"];
 *  Hash<<SQAT [ label="return"];
 *  Hash=>SQAT [ label = "LacSymQat_HashStatePrefixAadBufferPopulate()",
 *               URL="\ref LacSymQat_HashStatePrefixAadBufferPopulate()"];
 *  Hash<<SQAT [ label="return"];
 *  Achain<<Hash [ label="return"];
 *  SYM<<Achain [ label = "status" ];
 *  SYM=>SYM [label = "LAC_SYM_STAT_INC", URL="\ref LAC_SYM_STAT_INC"];
 *  APP<<SYM [label = "status"];
 * \endmsc
 *
 * Perform Sequence Diagram: For all 3 modes, full packets and in-place.
 * \msc
 *  APP [label="Application"], SYM [label="Symmetric LAC"],
 *  Achain [label="Alg chain"], Hash, SQAT [label="Symmetric QAT"],
 *  QATCOMMS [label="QAT Comms"];
 *
 *  APP=>SYM [ label = "cpaCySymPerformOp()",
 *             URL="\ref cpaCySymPerformOp()"] ;
 *  SYM=>SYM [ label = "LacSymPerform_BufferParamCheck()",
 *              URL="\ref LacSymPerform_BufferParamCheck()"];
 *  SYM=>Achain [ label = "LacAlgChain_Perform()",
 *                URL="\ref LacAlgChain_Perform()"];
 *  Achain=>Achain [ label = "Lac_MemPoolEntryAlloc()",
 *                  URL="\ref Lac_MemPoolEntryAlloc()"];
 *  Achain=>SQAT [ label = "LacSymQat_packetTypeGet()",
 *               URL="\ref LacSymQat_packetTypeGet()"];
 *  Achain<<SQAT [ label="return"];
 *  Achain=>Achain [ label = "LacBuffDesc_BufferListTotalSizeGet()",
 *                  URL="\ref LacBuffDesc_BufferListTotalSizeGet()"];
 *  Achain=>Hash [ label = "LacHash_PerformParamCheck()",
 *                  URL = "\ref LacHash_PerformParamCheck()"];
 *  Achain<<Hash [ label="status"];
 *  Achain=>SQAT [ label = "LacSymQat_HashRequestParamsPopulate()",
 *               URL="\ref LacSymQat_HashRequestParamsPopulate()"];
 *  Achain<<SQAT [ label="return"];
 *  Achain<<SQAT [ label="cmdFlags"];
 *
 *  Achain=>Achain [ label = "LacBuffDesc_BufferListDescWrite()",
 *               URL="\ref LacBuffDesc_BufferListDescWrite()"];
 *  Achain=>SQAT [ label = "SalQatMsg_CmnMsgAndReqParamsPopulate()",
 *               URL="\ref SalQatMsg_CmnMsgAndReqParamsPopulate()"];
 *  Achain<<SQAT [ label="return"];
 *  Achain=>SYM [ label = "LacSymQueue_RequestSend()",
 *                URL="\ref LacSymQueue_RequestSend()"];
 *  SYM=>QATCOMMS [ label = "QatComms_MsgSend()",
 *                   URL="\ref QatComms_MsgSend()"];
 *  SYM<<QATCOMMS [ label="status"];
 *  Achain<<SYM   [ label="status"];
 *  SYM<<Achain [ label="status"];
 *  SYM=>SYM [label = "LAC_SYM_STAT_INC", URL="\ref LAC_SYM_STAT_INC"];
 *  APP<<SYM [label = "status"];
 *  ... [label = "QAT processing the request and generates response.
 *       Callback in Bottom Half Context"];
 *  ...;
 *  QATCOMMS=>QATCOMMS [label ="QatComms_ResponseMsgHandler()",
 *                       URL="\ref QatComms_ResponseMsgHandler()"];
 *  QATCOMMS=>SQAT [label ="LacSymQat_SymRespHandler()",
 *                   URL="\ref LacSymQat_SymRespHandler()"];
 *  SQAT=>SYM [label="LacSymCb_ProcessCallback()",
 *              URL="\ref LacSymCb_ProcessCallback()"];
 *  SYM=>SYM [label = "LacSymCb_ProcessCallbackInternal()",
 *            URL="\ref LacSymCb_ProcessCallbackInternal()"];
 *  SYM=>SYM [label = "Lac_MemPoolEntryFree()",
 *            URL="\ref Lac_MemPoolEntryFree()"];
 *  SYM=>SYM [label = "LAC_SYM_STAT_INC", URL="\ref LAC_SYM_STAT_INC"];
 *  SYM=>APP [label="cbFunc"];
 *  APP>>SYM [label="return"];
 *  SYM>>SQAT [label="return"];
 *  SQAT>>QATCOMMS [label="return"];
 * \endmsc
 *
 * @lld_end
 *
 *****************************************************************************/

/*****************************************************************************/

#ifndef LAC_SYM_HASH_H
#define LAC_SYM_HASH_H

/*
******************************************************************************
* Include public/global header files
******************************************************************************
*/

#include "cpa.h"
#include "cpa_cy_sym.h"

/*
*******************************************************************************
* Include private header files
*******************************************************************************
*/

#include "lac_session.h"
#include "lac_buffer_desc.h"

/**
 *****************************************************************************
 * @ingroup LacHash
 *      Definition of callback function.
 *
 * @description
 *      This is the callback function prototype. The callback function is
 *      invoked when a hash precompute operation completes.
 *
 * @param[in] pCallbackTag  Opaque value provided by user while making
 *                         individual function call.
 *
 * @retval
 *      None
 *****************************************************************************/
typedef void (*lac_hash_precompute_done_cb_t)(void *pCallbackTag);

/*
 * WARNING: There are no checks done on the parameters of the functions in
 * this file. The expected values of the parameters are documented and it is
 * up to the caller to provide valid values.
 */

/**
*******************************************************************************
* @ingroup LacHash
*      validate the hash context
*
* @description
*      The client populates the hash context in the session context structure
*      This is passed as parameter to the session register API function and
*      needs to be validated.
*
* @param[in] pHashSetupData      pointer to hash context structure
*
* @retval CPA_STATUS_SUCCESS        Success
* @retval CPA_STATUS_INVALID_PARAM  Invalid parameter
*
*****************************************************************************/
CpaStatus LacHash_HashContextCheck(CpaInstanceHandle instanceHandle,
                                   const CpaCySymHashSetupData *pHashSetupData);

/**
 ******************************************************************************
 * @ingroup LacHash
 *      Populate the hash pre-compute data.
 *
 * @description
 *      This function populates the state1 and state2 fields with the hash
 *      pre-computes.  This is only done for authentication.  The state1
 *      and state2 pointers must be set to point to the correct locations
 *      in the content descriptor where the precompute result(s) will be
 *      written, before this function is called.
 *
 * @param[in] instanceHandle    Instance Handle
 * @param[in] pSessionSetup     pointer to session setup data
 * @param[in] callbackFn        Callback function which is invoked when
 *                              the precompute operation is completed
 * @param[in] pCallbackTag       Opaque data which is passed back to the user
 *                              as a parameter in the callback function
 * @param[out] pWorkingBuffer   Pointer to working buffer, sufficient memory
 *                              must be allocated by the caller for this.
 *                              Assumption that this is 8 byte aligned.
 * @param[out] pState1          pointer to State 1 in content descriptor
 * @param[out] pState2          pointer to State 2 in content descriptor
 *
 * @retval CPA_STATUS_SUCCESS    Success
 * @retval CPA_STATUS_RETRY      Retry the operation.
 * @retval CPA_STATUS_RESOURCE   Error Allocating memory
 * @retval CPA_STATUS_FAIL       Operation Failed
 *
 *****************************************************************************/
CpaStatus LacHash_PrecomputeDataCreate(const CpaInstanceHandle instanceHandle,
                                       CpaCySymSessionSetupData *pSessionSetup,
                                       lac_hash_precompute_done_cb_t callbackFn,
                                       void *pCallbackTag,
                                       Cpa8U *pWorkingBuffer,
                                       Cpa8U *pState1,
                                       Cpa8U *pState2);

/**
 ******************************************************************************
 * @ingroup LacHash
 *      populate the hash state prefix aad buffer.
 *
 * @description
 *      This function populates the hash state prefix aad buffer. This function
 *      is not called for CCM/GCM operations as the AAD data varies per request
 *      and is stored in the cookie as opposed to the session descriptor.
 *
 * @param[in] pHashSetupData        pointer to hash setup structure
 * @param[in] pHashControlBlock     pointer to hash control block
 * @param[in] qatHashMode           QAT Mode for hash
 * @param[in] pHashStateBuffer      pointer to hash state prefix aad buffer
 * @param[in] pHashStateBufferInfo  Pointer to hash state prefix buffer info
 *
 * @retval CPA_STATUS_SUCCESS       Success
 * @retval CPA_STATUS_FAIL          Operation Failed
 *
 *****************************************************************************/
CpaStatus LacHash_StatePrefixAadBufferInit(
    sal_service_t *pService,
    const CpaCySymHashSetupData *pHashSetupData,
    icp_qat_la_bulk_req_ftr_t *pHashControlBlock,
    icp_qat_hw_auth_mode_t qatHashMode,
    Cpa8U *pHashStateBuffer,
    lac_sym_qat_hash_state_buffer_info_t *pHashStateBufferInfo);

/**
*******************************************************************************
* @ingroup LacHash
*      Check parameters for a hash perform operation
*
* @description
*      This function checks the parameters for a hash perform operation.
*
* @param[in] pSessionDesc        Pointer to session descriptor.
* @param[in] pOpData             Pointer to request parameters.
* @param[in] srcPktSize          Total size of the Buffer List
* @param[in] pVerifyResult       Pointer to user flag
*
* @retval CPA_STATUS_SUCCESS       Success
* @retval CPA_STATUS_INVALID_PARAM Invalid Parameter
*
*****************************************************************************/
CpaStatus LacHash_PerformParamCheck(CpaInstanceHandle instanceHandle,
                                    lac_session_desc_t *pSessionDesc,
                                    const CpaCySymOpData *pOpData,
                                    Cpa64U srcPktSize,
                                    const CpaBoolean *pVerifyResult);

/**
*******************************************************************************
* @ingroup LacHash
*      Perform hash precompute operation for HMAC
*
* @description
*      This function sends 2 requests to the CPM for the hmac precompute
*      operations. The results of the ipad and opad state calculation
*      is copied into pState1 and pState2 (e.g. these may be the state1 and
*      state2 buffers in a hash content descriptor) and when
*      the final operation has completed the condition passed as a param to
*      this function is set to true.
*
*      This function performs the XORing of the IPAD and OPAD constants to
*      the key (which was padded to the block size of the algorithm)
*
* @param[in]  instanceHandle       Instance Handle
* @param[in]  hashAlgorithm        Hash Algorithm
* @param[in]  authKeyLenInBytes    Length of Auth Key
* @param[in]  pAuthKey             Pointer to Auth Key
* @param[out] pWorkingMemory       Pointer to working memory that is carved
*                                  up and used in the pre-compute operations.
*                                  Assumption that this is 8 byte aligned.
* @param[out] pState1              Pointer to State 1 in content descriptor
* @param[out] pState2              Pointer to State 2 in content descriptor
* @param[in]  callbackFn           Callback function which is invoked when
*                                  the precompute operation is completed
* @param[in]  pCallbackTag         Opaque data which is passed back to the user
*                                  as a parameter in the callback function
*
* @retval CPA_STATUS_SUCCESS       Success
* @retval CPA_STATUS_RETRY         Retry the operation.
* @retval CPA_STATUS_FAIL          Operation Failed
*
*****************************************************************************/
CpaStatus LacSymHash_HmacPreComputes(CpaInstanceHandle instanceHandle,
                                     CpaCySymHashAlgorithm hashAlgorithm,
                                     Cpa32U authKeyLenInBytes,
                                     Cpa8U *pAuthKey,
                                     Cpa8U *pWorkingMemory,
                                     Cpa8U *pState1,
                                     Cpa8U *pState2,
                                     lac_hash_precompute_done_cb_t callbackFn,
                                     void *pCallbackTag);

/**
*******************************************************************************
 * @ingroup LacHash
 *      Perform hash precompute operation for XCBC MAC and GCM
 *
 * @description
 *      This function sends 1 request to the CPM for the precompute operation
 *      based on an AES ECB cipher. The results of the calculation is copied
 *      into pState (this may be a pointer to the State 2 buffer in a Hash
 *      content descriptor) and when the operation has completed the condition
 *      passed as a param to this function is set to true.
 *
 * @param[in]  instanceHandle       Instance Handle
 * @param[in]  hashAlgorithm        Hash Algorithm
 * @param[in]  authKeyLenInBytes    Length of Auth Key
 * @param[in]  pAuthKey             Auth Key
 * @param[out] pWorkingMemory       Pointer to working memory that is carved
 *                                  up and used in the pre-compute operations.
 *                                  Assumption that this is 8 byte aligned.
 * @param[out] pState               Pointer to output state
 * @param[in]  callbackFn           Callback function which is invoked when
 *                                  the precompute operation is completed
 * @param[in]  pCallbackTag         Opaque data which is passed back to the user
 *                                  as a parameter in the callback function

 *
 * @retval CPA_STATUS_SUCCESS       Success
 * @retval CPA_STATUS_RETRY         Retry the operation.
 * @retval CPA_STATUS_FAIL          Operation Failed
 *
 *****************************************************************************/
CpaStatus LacSymHash_AesECBPreCompute(CpaInstanceHandle instanceHandle,
                                      CpaCySymHashAlgorithm hashAlgorithm,
                                      Cpa32U authKeyLenInBytes,
                                      Cpa8U *pAuthKey,
                                      Cpa8U *pWorkingMemory,
                                      Cpa8U *pState,
                                      lac_hash_precompute_done_cb_t callbackFn,
                                      void *pCallbackTag);

/**
*******************************************************************************
* @ingroup LacHash
*      initialise data structures for the hash precompute operations
*
* @description
*      This function registers the precompute callback handler function, which
*      is different to the default one used by symmetric. Content descriptors
*      are pre-allocated for the hmac precomputes as they are constant for
*      these operations.
*
* @retval CPA_STATUS_SUCCESS       Success
* @retval CPA_STATUS_RESOURCE      Error allocating memory
*
*****************************************************************************/
CpaStatus LacSymHash_HmacPrecompInit(CpaInstanceHandle instanceHandle);

/**
*******************************************************************************
* @ingroup LacHash
*      free resources allocated for the precompute operations
*
* @description
*      free up the memory allocated on init time for the content descriptors
*      that were allocated for the HMAC precompute operations.
*
* @return none
*
*****************************************************************************/
void LacSymHash_HmacPrecompShutdown(CpaInstanceHandle instanceHandle);

#endif /* LAC_SYM_HASH_H */
