INSTINCT Code Coverage Report


Directory: src/
File: util/Random/SHA256.cpp
Date: 2025-07-19 10:51:51
Exec Total Coverage
Lines: 82 94 87.2%
Functions: 12 13 92.3%
Branches: 21 36 58.3%

Line Branch Exec Source
1 /*
2 MIT License
3
4 Copyright (c) 2021 Jérémy LAMBERT (SystemGlitch)
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24
25 // NOLINTBEGIN
26
27 #include "SHA256.hpp"
28
29 #include <cstring>
30 #include <iomanip>
31 #include <sstream>
32
33 #if defined(__clang__)
34 #pragma GCC diagnostic push
35 #pragma GCC diagnostic ignored "-Wsign-conversion"
36 #endif
37
38 #ifndef DOXYGEN_IGNORE
39
40 namespace NAV
41 {
42 constexpr std::array<uint32_t, 64> SHA256::K;
43
44 168 SHA256::SHA256() : m_blocklen(0), m_bitlen(0) // NOLINT
45 {
46 168 m_state[0] = 0x6a09e667;
47 168 m_state[1] = 0xbb67ae85;
48 168 m_state[2] = 0x3c6ef372;
49 168 m_state[3] = 0xa54ff53a;
50 168 m_state[4] = 0x510e527f;
51 168 m_state[5] = 0x9b05688c;
52 168 m_state[6] = 0x1f83d9ab;
53 168 m_state[7] = 0x5be0cd19;
54 168 }
55
56 167 void SHA256::update(const uint8_t* data, size_t length)
57 {
58
2/2
✓ Branch 0 taken 3141 times.
✓ Branch 1 taken 167 times.
3308 for (size_t i = 0; i < length; i++)
59 {
60 3141 m_data[m_blocklen++] = data[i]; // NOLINT
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3141 times.
3141 if (m_blocklen == 64)
62 {
63 transform();
64
65 // End of the block
66 m_bitlen += 512;
67 m_blocklen = 0;
68 }
69 }
70 167 }
71
72 168 void SHA256::update(const std::string& data)
73 {
74 168 update(reinterpret_cast<const uint8_t*>(data.c_str()), data.size()); // NOLINT
75 168 }
76
77 168 uint8_t* SHA256::digest()
78 {
79 168 uint8_t* hash = new uint8_t[32]; // NOLINT
80
81 168 pad();
82 168 revert(hash);
83
84 167 return hash;
85 }
86
87 93701 uint32_t SHA256::rotr(uint32_t x, uint32_t n)
88 {
89 93701 return (x >> n) | (x << (32 - n));
90 }
91
92 10642 uint32_t SHA256::choose(uint32_t e, uint32_t f, uint32_t g)
93 {
94 10642 return (e & f) ^ (~e & g);
95 }
96
97 10662 uint32_t SHA256::majority(uint32_t a, uint32_t b, uint32_t c)
98 {
99 10662 return (a & (b | c)) | (b & c);
100 }
101
102 7960 uint32_t SHA256::sig0(uint32_t x)
103 {
104 7960 return SHA256::rotr(x, 7) ^ SHA256::rotr(x, 18) ^ (x >> 3); // NOLINT
105 }
106
107 7966 uint32_t SHA256::sig1(uint32_t x)
108 {
109 7966 return SHA256::rotr(x, 17) ^ SHA256::rotr(x, 19) ^ (x >> 10); // NOLINT
110 }
111
112 168 void SHA256::transform()
113 {
114 uint32_t maj, xorA, ch, xorE, sum, newA, newE, m[64]; // NOLINT
115 uint32_t state[8]; // NOLINT
116
117
2/2
✓ Branch 0 taken 2680 times.
✓ Branch 1 taken 168 times.
2848 for (uint8_t i = 0, j = 0; i < 16; i++, j += 4)
118 { // Split data in 32 bit blocks for the 16 first words
119 2680 m[i] = (m_data[j] << 24) | (m_data[j + 1] << 16) | (m_data[j + 2] << 8) | (m_data[j + 3]); // NOLINT
120 }
121
122
2/2
✓ Branch 0 taken 7992 times.
✓ Branch 1 taken 168 times.
8160 for (uint8_t k = 16; k < 64; k++)
123 { // Remaining 48 blocks
124 7992 m[k] = SHA256::sig1(m[k - 2]) + m[k - 7] + SHA256::sig0(m[k - 15]) + m[k - 16]; // NOLINT
125 }
126
127
2/2
✓ Branch 0 taken 1344 times.
✓ Branch 1 taken 168 times.
1512 for (uint8_t i = 0; i < 8; i++)
128 {
129 1344 state[i] = m_state[i]; // NOLINT
130 }
131
132
2/2
✓ Branch 0 taken 10689 times.
✓ Branch 1 taken 168 times.
10857 for (uint8_t i = 0; i < 64; i++)
133 {
134 10689 maj = SHA256::majority(state[0], state[1], state[2]);
135 10648 xorA = SHA256::rotr(state[0], 2) ^ SHA256::rotr(state[0], 13) ^ SHA256::rotr(state[0], 22);
136
137 10659 ch = choose(state[4], state[5], state[6]);
138
139 10651 xorE = SHA256::rotr(state[4], 6) ^ SHA256::rotr(state[4], 11) ^ SHA256::rotr(state[4], 25);
140
141 10640 sum = m[i] + K[i] + state[7] + ch + xorE; // NOLINT
142 10689 newA = xorA + maj + sum;
143 10689 newE = state[3] + sum;
144
145 10689 state[7] = state[6];
146 10689 state[6] = state[5];
147 10689 state[5] = state[4];
148 10689 state[4] = newE;
149 10689 state[3] = state[2];
150 10689 state[2] = state[1];
151 10689 state[1] = state[0];
152 10689 state[0] = newA;
153 }
154
155
2/2
✓ Branch 0 taken 1341 times.
✓ Branch 1 taken 168 times.
1509 for (uint8_t i = 0; i < 8; i++)
156 {
157 1341 m_state[i] += state[i]; // NOLINT
158 }
159 168 }
160
161 168 void SHA256::pad()
162 {
163 168 uint64_t i = m_blocklen;
164
1/2
✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
168 uint8_t end = m_blocklen < 56 ? 56 : 64;
165
166 168 m_data[i++] = 0x80; // Append a bit 1 // NOLINT
167
2/2
✓ Branch 0 taken 6034 times.
✓ Branch 1 taken 168 times.
6202 while (i < end)
168 {
169 6034 m_data[i++] = 0x00; // Pad with zeros // NOLINT
170 }
171
172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 168 times.
168 if (m_blocklen >= 56)
173 {
174 transform();
175 memset(m_data, 0, 56); // NOLINT
176 }
177
178 // Append to the padding the total message's length in bits and transform.
179 168 m_bitlen += m_blocklen * 8; // NOLINT
180 168 m_data[63] = static_cast<uint8_t>(m_bitlen);
181 168 m_data[62] = static_cast<uint8_t>(m_bitlen >> 8); // NOLINT
182 168 m_data[61] = static_cast<uint8_t>(m_bitlen >> 16); // NOLINT
183 168 m_data[60] = static_cast<uint8_t>(m_bitlen >> 24); // NOLINT
184 168 m_data[59] = static_cast<uint8_t>(m_bitlen >> 32); // NOLINT
185 168 m_data[58] = static_cast<uint8_t>(m_bitlen >> 40); // NOLINT
186 168 m_data[57] = static_cast<uint8_t>(m_bitlen >> 48); // NOLINT
187 168 m_data[56] = static_cast<uint8_t>(m_bitlen >> 56); // NOLINT
188 168 transform();
189 167 }
190
191 168 void SHA256::revert(uint8_t* hash)
192 {
193 // SHA uses big endian byte ordering
194 // Revert all bytes
195
2/2
✓ Branch 0 taken 671 times.
✓ Branch 1 taken 168 times.
839 for (uint8_t i = 0; i < 4; i++)
196 {
197
2/2
✓ Branch 0 taken 5343 times.
✓ Branch 1 taken 671 times.
6014 for (uint8_t j = 0; j < 8; j++)
198 {
199 5343 hash[i + (j * 4)] = (m_state[j] >> (24 - i * 8)) & 0x000000ff; // NOLINT
200 }
201 }
202 168 }
203
204 std::string SHA256::toString(const uint8_t* digest)
205 {
206 std::stringstream s;
207 s << std::setfill('0') << std::hex;
208
209 for (uint8_t i = 0; i < 32; i++)
210 {
211 s << std::setw(2) << static_cast<unsigned int>(digest[i]); // NOLINT
212 }
213
214 return s.str();
215 }
216
217 } // namespace NAV
218
219 #endif
220
221 #if defined(__clang__)
222 #pragma GCC diagnostic pop
223 #endif
224 // NOLINTEND
225