LCOV - code coverage report
Current view: top level - pub_facility/util_func - tsd_sha256.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.2 % 204 188
Test Date: 2026-07-28 10:52:48 Functions: 100.0 % 28 28

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2026 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : #include "tsd_sha256.h"
      11              : #include <mutex>
      12              : #include <securec.h>
      13              : #include "common/type_def.h"
      14              : #include "tsd_log.h"
      15              : 
      16              : #if defined(__aarch64__)
      17              : #include <arm_neon.h>
      18              : #include <sys/auxv.h>
      19              : #include <asm/hwcap.h>
      20              : #define TSD_SHA256_PLATFORM_ARM 1
      21              : #define TSD_SHA256_PLATFORM_X86 0
      22              : #elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
      23              : #include <immintrin.h>
      24              : #define TSD_SHA256_PLATFORM_ARM 0
      25              : #define TSD_SHA256_PLATFORM_X86 1
      26              : #else
      27              : #define TSD_SHA256_PLATFORM_ARM 0
      28              : #define TSD_SHA256_PLATFORM_X86 0
      29              : #endif
      30              : 
      31              : namespace tsd {
      32              : namespace sha256 {
      33              : 
      34              : namespace {
      35              : 
      36              : constexpr uint32_t INITIAL_HASH[8] = {0x6a09e667U, 0xbb67ae85U, 0x3c6ef372U, 0xa54ff53aU,
      37              :                                       0x510e527fU, 0x9b05688cU, 0x1f83d9abU, 0x5be0cd19U};
      38              : 
      39              : constexpr uint32_t K[64] = {
      40              :     0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U,
      41              :     0xd807aa98U, 0x12835b01U, 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, 0xc19bf174U,
      42              :     0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU, 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU,
      43              :     0x983e5152U, 0xa831c66dU, 0xb00327c8U, 0xbf597fc7U, 0xc6e00bf3U, 0xd5a79147U, 0x06ca6351U, 0x14292967U,
      44              :     0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU, 0x53380d13U, 0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U,
      45              :     0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U, 0xd6990624U, 0xf40e3585U, 0x106aa070U,
      46              :     0x19a4c116U, 0x1e376c08U, 0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU, 0x682e6ff3U,
      47              :     0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U, 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U};
      48              : 
      49              : // ============================================================
      50              : // Software fallback (all platforms)
      51              : // ============================================================
      52              : 
      53      9455616 : inline uint32_t RotateRight(uint32_t x, uint32_t n) { return (x >> n) | (x << (32U - n)); }
      54              : 
      55      1050624 : inline uint32_t BigSigma0(uint32_t x) { return RotateRight(x, 2) ^ RotateRight(x, 13) ^ RotateRight(x, 22); }
      56      1050624 : inline uint32_t BigSigma1(uint32_t x) { return RotateRight(x, 6) ^ RotateRight(x, 11) ^ RotateRight(x, 25); }
      57       787968 : inline uint32_t SmallSigma0(uint32_t x) { return RotateRight(x, 7) ^ RotateRight(x, 18) ^ (x >> 3); }
      58       787968 : inline uint32_t SmallSigma1(uint32_t x) { return RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10); }
      59      1050624 : inline uint32_t Choose(uint32_t e, uint32_t f, uint32_t g) { return (e & f) ^ (~e & g); }
      60      1050624 : inline uint32_t Majority(uint32_t a, uint32_t b, uint32_t c) { return (a & b) ^ (a & c) ^ (b & c); }
      61              : 
      62       262656 : inline uint32_t LoadBigEndian32(const uint8_t* p)
      63              : {
      64       262656 :     return (static_cast<uint32_t>(p[0]) << 24U) | (static_cast<uint32_t>(p[1]) << 16U) |
      65       262656 :            (static_cast<uint32_t>(p[2]) << 8U) | static_cast<uint32_t>(p[3]);
      66              : }
      67              : 
      68        16416 : void CompressBlockSoft(uint32_t state[8], const uint8_t* block)
      69              : {
      70        16416 :     uint32_t w[64];
      71       279072 :     for (int i = 0; i < 16; ++i) {
      72       262656 :         w[i] = LoadBigEndian32(block + i * 4);
      73              :     }
      74       804384 :     for (int i = 16; i < 64; ++i) {
      75       787968 :         w[i] = SmallSigma1(w[i - 2]) + w[i - 7] + SmallSigma0(w[i - 15]) + w[i - 16];
      76              :     }
      77              : 
      78        16416 :     uint32_t a = state[0], b = state[1], c = state[2], d = state[3];
      79        16416 :     uint32_t e = state[4], f = state[5], g = state[6], h = state[7];
      80              : 
      81      1067040 :     for (int i = 0; i < 64; ++i) {
      82      1050624 :         uint32_t t1 = h + BigSigma1(e) + Choose(e, f, g) + K[i] + w[i];
      83      1050624 :         uint32_t t2 = BigSigma0(a) + Majority(a, b, c);
      84      1050624 :         h = g;
      85      1050624 :         g = f;
      86      1050624 :         f = e;
      87      1050624 :         e = d + t1;
      88      1050624 :         d = c;
      89      1050624 :         c = b;
      90      1050624 :         b = a;
      91      1050624 :         a = t1 + t2;
      92              :     }
      93              : 
      94        16416 :     state[0] += a;
      95        16416 :     state[1] += b;
      96        16416 :     state[2] += c;
      97        16416 :     state[3] += d;
      98        16416 :     state[4] += e;
      99        16416 :     state[5] += f;
     100        16416 :     state[6] += g;
     101        16416 :     state[7] += h;
     102        16416 : }
     103              : 
     104              : // ============================================================
     105              : // ARM SHA2 Crypto Extensions (runtime detection via getauxval)
     106              : // ============================================================
     107              : #if TSD_SHA256_PLATFORM_ARM
     108              : 
     109              : static bool DetectArmCE()
     110              : {
     111              :     const unsigned long hwcap = getauxval(AT_HWCAP);
     112              :     return (hwcap & HWCAP_SHA2) != 0;
     113              : }
     114              : 
     115              : static const bool g_hasArmCE = DetectArmCE();
     116              : 
     117              : void CompressBlockArmCE(uint32_t state[8], const uint8_t* block)
     118              : {
     119              :     uint32x4_t abcd = vld1q_u32(&state[0]);
     120              :     uint32x4_t efgh = vld1q_u32(&state[4]);
     121              :     const uint32x4_t abcd_orig = abcd;
     122              :     const uint32x4_t efgh_orig = efgh;
     123              : 
     124              :     uint32x4_t msg0 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block)));
     125              :     uint32x4_t msg1 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block + 16)));
     126              :     uint32x4_t msg2 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block + 32)));
     127              :     uint32x4_t msg3 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block + 48)));
     128              : 
     129              :     uint32x4_t wk, abcd_prev;
     130              : 
     131              : #define SHA256_ROUND4_SCHED(i, m0, m1, m2, m3)  \
     132              :     wk = vaddq_u32(m0, vld1q_u32(&K[(i)]));     \
     133              :     abcd_prev = abcd;                           \
     134              :     abcd = vsha256hq_u32(abcd, efgh, wk);       \
     135              :     efgh = vsha256h2q_u32(efgh, abcd_prev, wk); \
     136              :     m0 = vsha256su1q_u32(vsha256su0q_u32(m0, m1), m2, m3)
     137              : 
     138              : #define SHA256_ROUND4_FINAL(i, m0)          \
     139              :     wk = vaddq_u32(m0, vld1q_u32(&K[(i)])); \
     140              :     abcd_prev = abcd;                       \
     141              :     abcd = vsha256hq_u32(abcd, efgh, wk);   \
     142              :     efgh = vsha256h2q_u32(efgh, abcd_prev, wk)
     143              : 
     144              :     SHA256_ROUND4_SCHED(0, msg0, msg1, msg2, msg3);
     145              :     SHA256_ROUND4_SCHED(4, msg1, msg2, msg3, msg0);
     146              :     SHA256_ROUND4_SCHED(8, msg2, msg3, msg0, msg1);
     147              :     SHA256_ROUND4_SCHED(12, msg3, msg0, msg1, msg2);
     148              :     SHA256_ROUND4_SCHED(16, msg0, msg1, msg2, msg3);
     149              :     SHA256_ROUND4_SCHED(20, msg1, msg2, msg3, msg0);
     150              :     SHA256_ROUND4_SCHED(24, msg2, msg3, msg0, msg1);
     151              :     SHA256_ROUND4_SCHED(28, msg3, msg0, msg1, msg2);
     152              :     SHA256_ROUND4_SCHED(32, msg0, msg1, msg2, msg3);
     153              :     SHA256_ROUND4_SCHED(36, msg1, msg2, msg3, msg0);
     154              :     SHA256_ROUND4_SCHED(40, msg2, msg3, msg0, msg1);
     155              :     SHA256_ROUND4_SCHED(44, msg3, msg0, msg1, msg2);
     156              :     SHA256_ROUND4_FINAL(48, msg0);
     157              :     SHA256_ROUND4_FINAL(52, msg1);
     158              :     SHA256_ROUND4_FINAL(56, msg2);
     159              :     SHA256_ROUND4_FINAL(60, msg3);
     160              : 
     161              : #undef SHA256_ROUND4_SCHED
     162              : #undef SHA256_ROUND4_FINAL
     163              : 
     164              :     vst1q_u32(&state[0], vaddq_u32(abcd, abcd_orig));
     165              :     vst1q_u32(&state[4], vaddq_u32(efgh, efgh_orig));
     166              : }
     167              : 
     168              : #endif // TSD_SHA256_PLATFORM_ARM
     169              : 
     170              : // ============================================================
     171              : // x86 SSSE3 + BMI2 accelerated path (runtime detection)
     172              : // SSSE3: Intel Core 2 2007+ / AMD Bulldozer 2011+
     173              : // BMI2:  Intel Haswell 2013+ / AMD Zen 2017+
     174              : // Uses 128-bit XMM (not 256-bit YMM) intentionally:
     175              : //   - 256-bit store → 32-bit scalar load triggers partial-width
     176              : //     store-to-load forwarding stalls (~15 cycles each on Intel).
     177              : //   - 128-bit store → 32-bit scalar load forwards cleanly.
     178              : //   - No AVX-SSE state transition overhead.
     179              : // BMI2 RORX: no FLAGS write, breaks false dependency chain in
     180              : // schedule expansion and compression, improving OOO scheduling.
     181              : // ============================================================
     182              : #if TSD_SHA256_PLATFORM_X86
     183              : 
     184            1 : static bool DetectX86Ssse3Bmi2() { return __builtin_cpu_supports("ssse3") && __builtin_cpu_supports("bmi2"); }
     185              : 
     186              : static const bool g_hasSsse3Bmi2 = DetectX86Ssse3Bmi2();
     187              : 
     188              : // _rorx_u32 requires __BMI2__ defined at parse time (header guard), but
     189              : // __attribute__((target("bmi2"))) only affects code-gen, not header parsing.
     190              : // Use a portable rotation helper; with target("bmi2") + -O2 the compiler
     191              : // recognizes the rotate idiom and emits the RORX instruction.
     192     94233024 : static inline uint32_t Ror32(uint32_t x, unsigned imm) noexcept { return (x >> imm) | (x << (32U - imm)); }
     193              : 
     194       163599 : __attribute__((target("ssse3,bmi2"))) void CompressBlockSsse3Bmi2(uint32_t state[8], const uint8_t* block)
     195              : {
     196              :     // Load 16 message words with SSSE3 byte-swap, 4 words (128-bit) at a time.
     197              :     // 128-bit stores allow clean 32-bit scalar forwarding in the schedule loop.
     198       163599 :     const __m128i BSWAP = _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3);
     199       163599 :     uint32_t w[64];
     200       817995 :     for (int i = 0; i < 16; i += 4) {
     201       654396 :         _mm_storeu_si128(
     202              :             PtrToPtr<uint32_t, __m128i>(&w[i]),
     203       654396 :             _mm_shuffle_epi8(_mm_loadu_si128(PtrToPtr<const uint8_t, const __m128i>(block + i * 4)), BSWAP));
     204              :     }
     205              : 
     206      8016351 :     for (int i = 16; i < 64; ++i) {
     207      7852752 :         const uint32_t s0 = Ror32(w[i - 15], 7) ^ Ror32(w[i - 15], 18) ^ (w[i - 15] >> 3);
     208      7852752 :         const uint32_t s1 = Ror32(w[i - 2], 17) ^ Ror32(w[i - 2], 19) ^ (w[i - 2] >> 10);
     209      7852752 :         w[i] = w[i - 16] + s0 + w[i - 7] + s1;
     210              :     }
     211              : 
     212       163599 :     uint32_t a = state[0], b = state[1], c = state[2], d = state[3];
     213       163599 :     uint32_t e = state[4], f = state[5], g = state[6], h = state[7];
     214              : 
     215     10633935 :     for (int i = 0; i < 64; ++i) {
     216     10470336 :         const uint32_t S1 = Ror32(e, 6) ^ Ror32(e, 11) ^ Ror32(e, 25);
     217     10470336 :         const uint32_t ch = (e & f) ^ (~e & g);
     218     10470336 :         const uint32_t t1 = h + S1 + ch + K[i] + w[i];
     219     10470336 :         const uint32_t S0 = Ror32(a, 2) ^ Ror32(a, 13) ^ Ror32(a, 22);
     220     10470336 :         const uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
     221     10470336 :         const uint32_t t2 = S0 + maj;
     222     10470336 :         h = g;
     223     10470336 :         g = f;
     224     10470336 :         f = e;
     225     10470336 :         e = d + t1;
     226     10470336 :         d = c;
     227     10470336 :         c = b;
     228     10470336 :         b = a;
     229     10470336 :         a = t1 + t2;
     230              :     }
     231              : 
     232       163599 :     state[0] += a;
     233       163599 :     state[1] += b;
     234       163599 :     state[2] += c;
     235       163599 :     state[3] += d;
     236       163599 :     state[4] += e;
     237       163599 :     state[5] += f;
     238       163599 :     state[6] += g;
     239       163599 :     state[7] += h;
     240       163599 : }
     241              : 
     242              : #endif // TSD_SHA256_PLATFORM_X86
     243              : 
     244              : // ============================================================
     245              : // Dispatch
     246              : // ============================================================
     247              : 
     248           35 : inline void StoreBigEndian64(uint8_t* p, uint64_t v)
     249              : {
     250           35 :     p[0] = static_cast<uint8_t>(v >> 56U);
     251           35 :     p[1] = static_cast<uint8_t>(v >> 48U);
     252           35 :     p[2] = static_cast<uint8_t>(v >> 40U);
     253           35 :     p[3] = static_cast<uint8_t>(v >> 32U);
     254           35 :     p[4] = static_cast<uint8_t>(v >> 24U);
     255           35 :     p[5] = static_cast<uint8_t>(v >> 16U);
     256           35 :     p[6] = static_cast<uint8_t>(v >> 8U);
     257           35 :     p[7] = static_cast<uint8_t>(v);
     258           35 : }
     259              : 
     260          280 : inline void StoreBigEndian32(uint8_t* p, uint32_t v)
     261              : {
     262          280 :     p[0] = static_cast<uint8_t>(v >> 24U);
     263          280 :     p[1] = static_cast<uint8_t>(v >> 16U);
     264          280 :     p[2] = static_cast<uint8_t>(v >> 8U);
     265          280 :     p[3] = static_cast<uint8_t>(v);
     266          280 : }
     267              : 
     268           23 : void LogSha256Backend()
     269              : {
     270           23 :     static std::once_flag logOnce;
     271           23 :     std::call_once(logOnce, []() {
     272              : #if TSD_SHA256_PLATFORM_ARM
     273              :         if (g_hasArmCE) {
     274              :             TSD_INFO("[TsdSha256] Using ARM SHA2 Crypto Extensions accelerated path.");
     275              :         } else {
     276              :             TSD_INFO("[TsdSha256] ARM SHA2 CE not available, using software fallback path.");
     277              :         }
     278              : #elif TSD_SHA256_PLATFORM_X86
     279            1 :         if (g_hasSsse3Bmi2) {
     280            1 :             TSD_INFO("[TsdSha256] Using x86 SSSE3+BMI2 accelerated path.");
     281              :         } else {
     282            0 :             TSD_INFO("[TsdSha256] x86 SSSE3+BMI2 not available, using software fallback path.");
     283              :         }
     284              : #else
     285              :         TSD_INFO("[TsdSha256] Unknown platform, using software fallback path.");
     286              : #endif
     287            1 :     });
     288           23 : }
     289              : 
     290       163599 : inline void CompressBlock(uint32_t state[8], const uint8_t* block)
     291              : {
     292              : #if TSD_SHA256_PLATFORM_ARM
     293              :     if (g_hasArmCE) {
     294              :         CompressBlockArmCE(state, block);
     295              :     } else {
     296              :         CompressBlockSoft(state, block);
     297              :     }
     298              : #elif TSD_SHA256_PLATFORM_X86
     299       163599 :     if (g_hasSsse3Bmi2) {
     300       163599 :         CompressBlockSsse3Bmi2(state, block);
     301              :     } else {
     302            0 :         CompressBlockSoft(state, block);
     303              :     }
     304              : #else
     305              :     CompressBlockSoft(state, block);
     306              : #endif
     307       163599 : }
     308              : 
     309              : using CompressFn = void (*)(uint32_t*, const uint8_t*);
     310              : 
     311           36 : void UpdateCore(Context& ctx, const uint8_t* data, size_t len, CompressFn compress)
     312              : {
     313           36 :     const size_t origLen = len;
     314              : 
     315           36 :     if (ctx.bufLen > 0) {
     316            1 :         const uint32_t fill = SHA256_BLOCK_SIZE - ctx.bufLen;
     317            1 :         if (len < fill) {
     318            1 :             const errno_t err = memcpy_s(ctx.buffer + ctx.bufLen, SHA256_BLOCK_SIZE - ctx.bufLen, data, len);
     319            1 :             if (err != EOK) {
     320              :                 return;
     321              :             }
     322            1 :             ctx.bufLen += static_cast<uint32_t>(len % SHA256_BLOCK_SIZE);
     323            1 :             ctx.totalLen += origLen;
     324            1 :             return;
     325              :         }
     326            0 :         const errno_t err = memcpy_s(ctx.buffer + ctx.bufLen, SHA256_BLOCK_SIZE - ctx.bufLen, data, fill);
     327            0 :         if (err != EOK) {
     328              :             return;
     329              :         }
     330            0 :         compress(ctx.state, ctx.buffer);
     331            0 :         data += fill;
     332            0 :         len -= fill;
     333            0 :         ctx.bufLen = 0;
     334              :     }
     335              : 
     336       180013 :     while (len >= SHA256_BLOCK_SIZE) {
     337       179978 :         compress(ctx.state, data);
     338       179978 :         data += SHA256_BLOCK_SIZE;
     339       179978 :         len -= SHA256_BLOCK_SIZE;
     340              :     }
     341              : 
     342           35 :     if (len > 0) {
     343           27 :         const errno_t err = memcpy_s(ctx.buffer, SHA256_BLOCK_SIZE, data, len);
     344           27 :         if (err != EOK) {
     345              :             return;
     346              :         }
     347           27 :         ctx.bufLen = static_cast<uint32_t>(len % SHA256_BLOCK_SIZE);
     348              :     }
     349              : 
     350           35 :     ctx.totalLen += origLen;
     351              : }
     352              : 
     353           35 : void FinalCore(Context& ctx, uint8_t* hash, CompressFn compress)
     354              : {
     355           35 :     const uint64_t totalBits = ctx.totalLen * 8U;
     356              : 
     357           35 :     ctx.buffer[ctx.bufLen++] = 0x80U;
     358              : 
     359           35 :     if (ctx.bufLen > 56U) {
     360            2 :         const errno_t err =
     361            2 :             memset_s(ctx.buffer + ctx.bufLen, SHA256_BLOCK_SIZE - ctx.bufLen, 0, SHA256_BLOCK_SIZE - ctx.bufLen);
     362            2 :         if (err != EOK) {
     363              :             return;
     364              :         }
     365            2 :         compress(ctx.state, ctx.buffer);
     366            2 :         ctx.bufLen = 0;
     367              :     }
     368              : 
     369           35 :     const errno_t err = memset_s(ctx.buffer + ctx.bufLen, SHA256_BLOCK_SIZE - ctx.bufLen, 0, 56U - ctx.bufLen);
     370           35 :     if (err != EOK) {
     371              :         return;
     372              :     }
     373              : 
     374           35 :     StoreBigEndian64(ctx.buffer + 56U, totalBits);
     375           35 :     compress(ctx.state, ctx.buffer);
     376              : 
     377          315 :     for (int i = 0; i < 8; ++i) {
     378          280 :         StoreBigEndian32(hash + i * 4, ctx.state[i]);
     379              :     }
     380              : }
     381              : 
     382              : } // anonymous namespace
     383              : 
     384           35 : void Init(Context& ctx)
     385              : {
     386          315 :     for (int i = 0; i < 8; ++i) {
     387          280 :         ctx.state[i] = INITIAL_HASH[i];
     388              :     }
     389           35 :     ctx.totalLen = 0;
     390           35 :     ctx.bufLen = 0;
     391           35 : }
     392              : 
     393           23 : void Update(Context& ctx, const uint8_t* data, size_t len)
     394              : {
     395           23 :     if (data == nullptr && len > 0) {
     396            0 :         TSD_ERROR("[TsdSha256] Update called with nullptr data and non-zero len.");
     397            0 :         return;
     398              :     }
     399           23 :     LogSha256Backend();
     400           23 :     UpdateCore(ctx, data, len, CompressBlock);
     401              : }
     402              : 
     403           22 : void Final(Context& ctx, uint8_t* hash)
     404              : {
     405           22 :     if (hash == nullptr) {
     406            0 :         TSD_ERROR("[TsdSha256] Final called with nullptr hash.");
     407            0 :         return;
     408              :     }
     409           22 :     FinalCore(ctx, hash, CompressBlock);
     410              : }
     411              : 
     412           21 : void Compute(const uint8_t* data, size_t len, uint8_t* hash)
     413              : {
     414           21 :     Context ctx;
     415           21 :     Init(ctx);
     416           21 :     Update(ctx, data, len);
     417           21 :     Final(ctx, hash);
     418           21 : }
     419              : 
     420           21 : std::string ComputeHexString(const uint8_t* data, size_t len)
     421              : {
     422           21 :     if (data == nullptr && len > 0) {
     423            0 :         TSD_ERROR("[TsdSha256] ComputeHexString called with nullptr data and non-zero len.");
     424            0 :         return "";
     425              :     }
     426           21 :     uint8_t hash[DIGEST_LENGTH];
     427           21 :     Compute(data, len, hash);
     428           21 :     constexpr char hexDigits[] = "0123456789abcdef";
     429           21 :     std::string result;
     430           21 :     result.reserve(DIGEST_LENGTH * 2);
     431          693 :     for (uint32_t i = 0; i < DIGEST_LENGTH; ++i) {
     432          672 :         result.push_back(hexDigits[hash[i] >> 4U]);
     433          672 :         result.push_back(hexDigits[hash[i] & 0x0FU]);
     434              :     }
     435           21 :     return result;
     436           21 : }
     437              : 
     438              : // ============================================================
     439              : // Software-only path (for UT verification)
     440              : // ============================================================
     441           13 : static void UpdateSoft(Context& ctx, const uint8_t* data, size_t len) { UpdateCore(ctx, data, len, CompressBlockSoft); }
     442              : 
     443           13 : static void FinalSoft(Context& ctx, uint8_t* hash) { FinalCore(ctx, hash, CompressBlockSoft); }
     444              : 
     445           13 : void ComputeSoft(const uint8_t* data, size_t len, uint8_t* hash)
     446              : {
     447           13 :     Context ctx;
     448           13 :     Init(ctx);
     449           13 :     UpdateSoft(ctx, data, len);
     450           13 :     FinalSoft(ctx, hash);
     451           13 : }
     452              : 
     453           13 : std::string ComputeHexStringSoft(const uint8_t* data, size_t len)
     454              : {
     455           13 :     if (data == nullptr && len > 0) {
     456            0 :         TSD_ERROR("[TsdSha256] ComputeHexStringSoft called with nullptr data and non-zero len.");
     457            0 :         return "";
     458              :     }
     459           13 :     uint8_t hash[DIGEST_LENGTH];
     460           13 :     ComputeSoft(data, len, hash);
     461           13 :     constexpr char hexDigits[] = "0123456789abcdef";
     462           13 :     std::string result;
     463           13 :     result.reserve(DIGEST_LENGTH * 2);
     464          429 :     for (uint32_t i = 0; i < DIGEST_LENGTH; ++i) {
     465          416 :         result.push_back(hexDigits[hash[i] >> 4U]);
     466          416 :         result.push_back(hexDigits[hash[i] & 0x0FU]);
     467              :     }
     468           13 :     return result;
     469           13 : }
     470              : 
     471              : } // namespace sha256
     472              : } // namespace tsd
        

Generated by: LCOV version 2.0-1