INSTINCT Code Coverage Report


Directory: src/
File: util/Random/SHA256.cpp
Date: 2025-11-25 23:34:18
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 167 SHA256::SHA256() : m_blocklen(0), m_bitlen(0) // NOLINT
45 {
46 167 m_state[0] = 0x6a09e667;
47 167 m_state[1] = 0xbb67ae85;
48 167 m_state[2] = 0x3c6ef372;
49 167 m_state[3] = 0xa54ff53a;
50 167 m_state[4] = 0x510e527f;
51 167 m_state[5] = 0x9b05688c;
52 167 m_state[6] = 0x1f83d9ab;
53 167 m_state[7] = 0x5be0cd19;
54 167 }
55
56 168 void SHA256::update(const uint8_t* data, size_t length)
57 {
58
2/2
✓ Branch 0 taken 3144 times.
✓ Branch 1 taken 168 times.
3312 for (size_t i = 0; i < length; i++)
59 {
60 3144 m_data[m_blocklen++] = data[i]; // NOLINT
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3144 times.
3144 if (m_blocklen == 64)
62 {
63 transform();
64
65 // End of the block
66 m_bitlen += 512;
67 m_blocklen = 0;
68 }
69 }
70 168 }
71
72 167 void SHA256::update(const std::string& data)
73 {
74 167 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 168 return hash;
85 }
86
87 90091 uint32_t SHA256::rotr(uint32_t x, uint32_t n)
88 {
89 90091 return (x >> n) | (x << (32 - n));
90 }
91
92 10479 uint32_t SHA256::choose(uint32_t e, uint32_t f, uint32_t g)
93 {
94 10479 return (e & f) ^ (~e & g);
95 }
96
97 10528 uint32_t SHA256::majority(uint32_t a, uint32_t b, uint32_t c)
98 {
99 10528 return (a & (b | c)) | (b & c);
100 }
101
102 7874 uint32_t SHA256::sig0(uint32_t x)
103 {
104 7874 return SHA256::rotr(x, 7) ^ SHA256::rotr(x, 18) ^ (x >> 3); // NOLINT
105 }
106
107 7887 uint32_t SHA256::sig1(uint32_t x)
108 {
109 7887 return SHA256::rotr(x, 17) ^ SHA256::rotr(x, 19) ^ (x >> 10); // NOLINT
110 }
111
112 167 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 2661 times.
✓ Branch 1 taken 167 times.
2828 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 2661 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 7911 times.
✓ Branch 1 taken 168 times.
8079 for (uint8_t k = 16; k < 64; k++)
123 { // Remaining 48 blocks
124 7911 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 10583 times.
✓ Branch 1 taken 168 times.
10751 for (uint8_t i = 0; i < 64; i++)
133 {
134 10583 maj = SHA256::majority(state[0], state[1], state[2]);
135 10508 xorA = SHA256::rotr(state[0], 2) ^ SHA256::rotr(state[0], 13) ^ SHA256::rotr(state[0], 22);
136
137 10501 ch = choose(state[4], state[5], state[6]);
138
139 10505 xorE = SHA256::rotr(state[4], 6) ^ SHA256::rotr(state[4], 11) ^ SHA256::rotr(state[4], 25);
140
141 10530 sum = m[i] + K[i] + state[7] + ch + xorE; // NOLINT
142 10583 newA = xorA + maj + sum;
143 10583 newE = state[3] + sum;
144
145 10583 state[7] = state[6];
146 10583 state[6] = state[5];
147 10583 state[5] = state[4];
148 10583 state[4] = newE;
149 10583 state[3] = state[2];
150 10583 state[2] = state[1];
151 10583 state[1] = state[0];
152 10583 state[0] = newA;
153 }
154
155
2/2
✓ Branch 0 taken 1344 times.
✓ Branch 1 taken 168 times.
1512 for (uint8_t i = 0; i < 8; i++)
156 {
157 1344 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 6013 times.
✓ Branch 1 taken 168 times.
6181 while (i < end)
168 {
169 6013 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 168 }
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 672 times.
✓ Branch 1 taken 168 times.
840 for (uint8_t i = 0; i < 4; i++)
196 {
197
2/2
✓ Branch 0 taken 5362 times.
✓ Branch 1 taken 672 times.
6034 for (uint8_t j = 0; j < 8; j++)
198 {
199 5362 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