LCOV - code coverage report
Current view: top level - libs/sha512/tests/src - test_libsha512_utils.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 99 99
Test Date: 2026-07-12 01:01:34 Functions: 100.0 % 5 5
Branches: 62.5 % 8 5

             Branch data     Line data    Source code
       1                 :             : #include "test_libsha512_utils.h"
       2                 :             : 
       3                 :             : #include "monocypher-ed25519.h"
       4                 :             : 
       5                 :             : /**
       6                 :             :  * @brief Hash one complete message with libsha512
       7                 :             :  * @details This helper gives tests a small, readable way to ask libsha512 for
       8                 :             :  * the digest of a message. The digest is stored in a libmem descriptor so the
       9                 :             :  * tests exercise the same memory-management style used by the other libraries
      10                 :             :  *
      11                 :             :  * @param message Message bytes that should be hashed
      12                 :             :  * @param message_size Number of bytes from @p message to include in the hash
      13                 :             :  * @param digest Output descriptor that receives the 64-byte SHA-512 digest
      14                 :             :  * @return SUCCESS when the digest was written, otherwise FAILURE
      15                 :             :  */
      16                 :          11 : Return calculate_sha512_digest(
      17                 :             :         const unsigned char *message,
      18                 :             :         size_t              message_size,
      19                 :             :         memory              *digest)
      20                 :             : {
      21                 :             :         /* Status returned by this function through provide()
      22                 :             :            Default value assumes successful completion */
      23                 :          11 :         Return status = SUCCESS;
      24                 :             : 
      25                 :          11 :         SHA512_Context context = {0};
      26                 :          11 :         unsigned char *digest_data = NULL;
      27                 :             : 
      28                 :             :         /* Validate the public helper inputs before allocating the digest buffer */
      29                 :          11 :         ASSERT(message != NULL);
      30                 :          11 :         ASSERT(digest != NULL);
      31                 :          11 :         ASSERT(SUCCESS == m_resize(digest,SHA512_DIGEST_LENGTH,ZERO_NEW_MEMORY));
      32                 :             : 
      33                 :             :         /* Convert the digest descriptor to writable bytes after it has the required
      34                 :             :            SHA-512 digest length */
      35                 :          11 :         IF(digest != NULL)
      36                 :             :         {
      37                 :          11 :                 digest_data = m_data(unsigned char,digest);
      38                 :             :         }
      39                 :             : 
      40                 :             :         /* Drive the normal one-shot SHA-512 flow: initialize, feed bytes, finalize */
      41                 :          11 :         ASSERT(digest_data != NULL);
      42                 :          11 :         ASSERT(CRYPT_OK == sha512_init(&context));
      43                 :          11 :         ASSERT(CRYPT_OK == sha512_update(&context,message,message_size));
      44                 :          11 :         ASSERT(CRYPT_OK == sha512_final(&context,digest_data));
      45                 :             : 
      46                 :          11 :         provide(status);
      47                 :             : }
      48                 :             : 
      49                 :             : /**
      50                 :             :  * @brief Hash one complete message with Monocypher SHA512
      51                 :             :  * @details The tests use this helper as an independent reference implementation
      52                 :             :  * for libsha512. It keeps Monocypher setup and length validation in one place
      53                 :             :  * while the individual tests stay focused on the input shape they exercise
      54                 :             :  *
      55                 :             :  * @param message Message bytes that should be hashed
      56                 :             :  * @param message_size Number of bytes from @p message to include in the hash
      57                 :             :  * @param digest Output descriptor that receives the 64-byte SHA-512 digest
      58                 :             :  * @return SUCCESS when Monocypher produced one SHA-512 digest, otherwise FAILURE
      59                 :             :  */
      60                 :          11 : Return calculate_sha512_digest_monocypher(
      61                 :             :         const unsigned char *message,
      62                 :             :         size_t              message_size,
      63                 :             :         memory              *digest)
      64                 :             : {
      65                 :             :         /* Status returned by this function through provide()
      66                 :             :            Default value assumes successful completion */
      67                 :          11 :         Return status = SUCCESS;
      68                 :             : 
      69                 :          11 :         unsigned char *digest_data = NULL;
      70                 :             : 
      71                 :          11 :         ASSERT(message != NULL);
      72                 :          11 :         ASSERT(digest != NULL);
      73                 :          11 :         ASSERT(SUCCESS == m_resize(digest,SHA512_DIGEST_LENGTH,ZERO_NEW_MEMORY));
      74                 :             : 
      75                 :          11 :         IF(digest != NULL)
      76                 :             :         {
      77                 :          11 :                 digest_data = m_data(unsigned char,digest);
      78                 :             :         }
      79                 :             : 
      80                 :          11 :         ASSERT(digest_data != NULL);
      81                 :             : 
      82         [ +  - ]:          11 :         if(SUCCESS == status)
      83                 :             :         {
      84                 :          11 :                 crypto_sha512(digest_data,message,message_size);
      85                 :             :         }
      86                 :             : 
      87                 :          11 :         provide(status);
      88                 :             : }
      89                 :             : 
      90                 :             : /**
      91                 :             :  * @brief Hash one message by sending it to libsha512 in smaller pieces
      92                 :             :  * @details SHA-512 callers may provide input gradually instead of all at once.
      93                 :             :  * This helper checks that pattern by applying each requested chunk size to a
      94                 :             :  * single hash context and writing the final digest into a libmem descriptor
      95                 :             :  *
      96                 :             :  * @param message Full message bytes that should be hashed
      97                 :             :  * @param message_size Number of bytes available in @p message
      98                 :             :  * @param chunk_sizes Descriptor containing the piece sizes to feed in order
      99                 :             :  * @param digest Output descriptor that receives the 64-byte SHA-512 digest
     100                 :             :  * @return SUCCESS when every chunk was accepted and the digest was written
     101                 :             :  */
     102                 :          10 : Return calculate_sha512_digest_in_chunks(
     103                 :             :         const unsigned char *message,
     104                 :             :         size_t              message_size,
     105                 :             :         const memory        *chunk_sizes,
     106                 :             :         memory              *digest)
     107                 :             : {
     108                 :             :         /* Status returned by this function through provide()
     109                 :             :            Default value assumes successful completion */
     110                 :          10 :         Return status = SUCCESS;
     111                 :             : 
     112                 :          10 :         SHA512_Context context = {0};
     113                 :          10 :         const size_t *chunks = NULL;
     114                 :          10 :         unsigned char *digest_data = NULL;
     115                 :          10 :         size_t offset = 0U;
     116                 :             : 
     117                 :             :         /* Validate the message, chunk plan, and output descriptor before hashing */
     118                 :          10 :         ASSERT(message != NULL);
     119                 :          10 :         ASSERT(chunk_sizes != NULL);
     120                 :          10 :         ASSERT(digest != NULL);
     121                 :          10 :         ASSERT(chunk_sizes->length > 0U);
     122                 :          10 :         ASSERT(SUCCESS == m_resize(digest,SHA512_DIGEST_LENGTH,ZERO_NEW_MEMORY));
     123                 :             : 
     124                 :             :         /* Read chunk sizes from libmem and prepare writable storage for the digest */
     125                 :          10 :         IF(chunk_sizes != NULL)
     126                 :             :         {
     127                 :          10 :                 chunks = m_data_ro(size_t,chunk_sizes);
     128                 :             :         }
     129                 :             : 
     130                 :          10 :         IF(digest != NULL)
     131                 :             :         {
     132                 :          10 :                 digest_data = m_data(unsigned char,digest);
     133                 :             :         }
     134                 :             : 
     135                 :          10 :         ASSERT(chunks != NULL);
     136                 :          10 :         ASSERT(digest_data != NULL);
     137                 :          10 :         ASSERT(CRYPT_OK == sha512_init(&context));
     138                 :             : 
     139                 :             :         /* Feed each requested chunk in order. The bounds checks keep the chunk plan
     140                 :             :            honest, so the final digest represents exactly the message under test */
     141   [ +  -  +  + ]:          76 :         for(size_t chunk_index = 0U; SUCCESS == status && chunk_index < chunk_sizes->length; chunk_index++)
     142                 :             :         {
     143                 :          66 :                 ASSERT(offset <= message_size);
     144                 :          66 :                 ASSERT(chunks[chunk_index] <= message_size - offset);
     145                 :             : 
     146         [ +  - ]:          66 :                 if(SUCCESS == status)
     147                 :             :                 {
     148                 :          66 :                         ASSERT(CRYPT_OK == sha512_update(&context,message + offset,chunks[chunk_index]));
     149                 :          66 :                         offset += chunks[chunk_index];
     150                 :             :                 }
     151                 :             :         }
     152                 :             : 
     153                 :             :         /* Confirm that the chunk plan consumed the full message, then write the
     154                 :             :            digest from the completed SHA-512 context */
     155                 :          10 :         ASSERT(offset == message_size);
     156                 :          10 :         ASSERT(CRYPT_OK == sha512_final(&context,digest_data));
     157                 :             : 
     158                 :          10 :         provide(status);
     159                 :             : }
     160                 :             : 
     161                 :             : /**
     162                 :             :  * @brief Compare two SHA-512 digest descriptors
     163                 :             :  * @details The check validates descriptor shape before comparing bytes, so a
     164                 :             :  * failing test points either to malformed test data or to a digest mismatch
     165                 :             :  *
     166                 :             :  * @param digest Digest produced by the code under test
     167                 :             :  * @param expected_digest Digest that the test expects
     168                 :             :  * @return SUCCESS when both descriptors contain the same 64 digest bytes
     169                 :             :  */
     170                 :          25 : Return assert_sha512_digest_matches(
     171                 :             :         const memory *digest,
     172                 :             :         const memory *expected_digest)
     173                 :             : {
     174                 :             :         /* Status returned by this function through provide()
     175                 :             :            Default value assumes successful completion */
     176                 :          25 :         Return status = SUCCESS;
     177                 :             : 
     178                 :          25 :         const unsigned char *digest_data = NULL;
     179                 :          25 :         const unsigned char *expected_data = NULL;
     180                 :          25 :         size_t digest_size = 0U;
     181                 :          25 :         size_t expected_size = 0U;
     182                 :             : 
     183                 :             :         /* First verify descriptor shape. A length failure is easier to understand
     184                 :             :            than a raw byte comparison against malformed data */
     185                 :          25 :         ASSERT(digest != NULL);
     186                 :          25 :         ASSERT(expected_digest != NULL);
     187                 :          25 :         ASSERT(digest->length == SHA512_DIGEST_LENGTH);
     188                 :          25 :         ASSERT(expected_digest->length == SHA512_DIGEST_LENGTH);
     189                 :          25 :         ASSERT(SUCCESS == m_guarded_byte_size(digest,digest->length,&digest_size));
     190                 :          25 :         ASSERT(SUCCESS == m_guarded_byte_size(expected_digest,expected_digest->length,&expected_size));
     191                 :          25 :         ASSERT(digest_size == SHA512_DIGEST_LENGTH);
     192                 :          25 :         ASSERT(expected_size == SHA512_DIGEST_LENGTH);
     193                 :             : 
     194                 :             :         /* Pull out read-only byte pointers only after descriptor validation passes */
     195                 :          25 :         IF(digest != NULL)
     196                 :             :         {
     197                 :          25 :                 digest_data = m_data_ro(unsigned char,digest);
     198                 :             :         }
     199                 :             : 
     200                 :          25 :         IF(expected_digest != NULL)
     201                 :             :         {
     202                 :          25 :                 expected_data = m_data_ro(unsigned char,expected_digest);
     203                 :             :         }
     204                 :             : 
     205                 :          25 :         ASSERT(digest_data != NULL);
     206                 :          25 :         ASSERT(expected_data != NULL);
     207                 :             : 
     208                 :             :         /* Finally compare the digest bytes themselves */
     209                 :          25 :         IF(digest_data != NULL && expected_data != NULL)
     210                 :             :         {
     211                 :          25 :                 ASSERT(0 == memcmp(digest_data,expected_data,(size_t)SHA512_DIGEST_LENGTH));
     212                 :             :         }
     213                 :             : 
     214                 :          25 :         provide(status);
     215                 :             : }
     216                 :             : 
     217                 :             : /**
     218                 :             :  * @brief Run one human-readable SHA-512 reference case
     219                 :             :  * @details The vector describes a message and the digest that public SHA-512
     220                 :             :  * references say it must produce. This helper prepares the message through
     221                 :             :  * libmem, hashes it, and compares the result with the expected bytes
     222                 :             :  *
     223                 :             :  * @param vector Message text and expected digest bytes for one reference case
     224                 :             :  * @return SUCCESS when libsha512 returns the expected digest
     225                 :             :  */
     226                 :           4 : Return check_sha512_vector(const sha512_digest_vector *vector)
     227                 :             : {
     228                 :             :         /* Status returned by this function through provide()
     229                 :             :            Default value assumes successful completion */
     230                 :           4 :         Return status = SUCCESS;
     231                 :             : 
     232                 :           4 :         size_t message_length = 0U;
     233                 :             : 
     234                 :           4 :         m_create(char,message,MEMORY_STRING);
     235                 :           4 :         m_create(unsigned char,digest);
     236                 :           4 :         m_create(unsigned char,expected_digest);
     237                 :           4 :         m_create(unsigned char,monocypher_digest);
     238                 :             : 
     239                 :             :         /* Validate the vector and copy its text into libmem-managed storage. The
     240                 :             :            string length check catches accidental vector size drift */
     241                 :           4 :         ASSERT(vector != NULL);
     242                 :           4 :         ASSERT(vector->message_text != NULL);
     243                 :           4 :         ASSERT(vector->expected_digest != NULL);
     244                 :           4 :         ASSERT(SUCCESS == m_copy_fixed_string(message,vector->message_size + 1U,vector->message_text));
     245                 :           4 :         ASSERT(SUCCESS == m_string_length(message,&message_length));
     246                 :           4 :         ASSERT(message_length == vector->message_size);
     247                 :             : 
     248                 :             :         /* Hash the prepared message and copy the expected digest into the same
     249                 :             :            descriptor style before comparing both byte arrays */
     250                 :           4 :         ASSERT(SUCCESS == calculate_sha512_digest(
     251                 :             :                 (const unsigned char *)m_text(message),
     252                 :             :                 message_length,
     253                 :             :                 digest));
     254                 :           4 :         ASSERT(SUCCESS == calculate_sha512_digest_monocypher(
     255                 :             :                 (const unsigned char *)m_text(message),
     256                 :             :                 message_length,
     257                 :             :                 monocypher_digest));
     258                 :           4 :         ASSERT(SUCCESS == m_copy_buffer(
     259                 :             :                 expected_digest,
     260                 :             :                 SHA512_DIGEST_LENGTH,
     261                 :             :                 vector->expected_digest));
     262                 :           4 :         ASSERT(SUCCESS == assert_sha512_digest_matches(expected_digest,monocypher_digest));
     263                 :           4 :         ASSERT(SUCCESS == assert_sha512_digest_matches(digest,monocypher_digest));
     264                 :             : 
     265                 :             :         /* Clean up every descriptor even when a vector assertion fails */
     266                 :           4 :         call(m_del(message));
     267                 :           4 :         call(m_del(digest));
     268                 :           4 :         call(m_del(expected_digest));
     269                 :           4 :         call(m_del(monocypher_digest));
     270                 :             : 
     271                 :           4 :         provide(status);
     272                 :             : }
        

Generated by: LCOV version 2.0-1