INSTINCT Code Coverage Report


Directory: src/
File: util/Random/SHA256.cpp
Date: 2025-06-02 15:19:59
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 168 void SHA256::update(const uint8_t* data, size_t length)
57 {
58
2/2
✓ Branch 0 taken 3155 times.
✓ Branch 1 taken 168 times.
3323 for (size_t i = 0; i < length; i++)
59 {
60 3155 m_data[m_blocklen++] = data[i]; // NOLINT
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3155 times.
3155 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 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 168 return hash;
85 }
86
87 93595 uint32_t SHA256::rotr(uint32_t x, uint32_t n)
88 {
89 93595 return (x >> n) | (x << (32 - n));
90 }
91
92 10670 uint32_t SHA256::choose(uint32_t e, uint32_t f, uint32_t g)
93 {
94 10670 return (e & f) ^ (~e & g);
95 }
96
97 10675 uint32_t SHA256::majority(uint32_t a, uint32_t b, uint32_t c)
98 {
99 10675 return (a & (b | c)) | (b & c);
100 }
101
102 7987 uint32_t SHA256::sig0(uint32_t x)
103 {
104 7987 return SHA256::rotr(x, 7) ^ SHA256::rotr(x, 18) ^ (x >> 3); // NOLINT
105 }
106
107 8001 uint32_t SHA256::sig1(uint32_t x)
108 {
109 8001 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 2681 times.
✓ Branch 1 taken 168 times.
2849 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 2681 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 8010 times.
✓ Branch 1 taken 168 times.
8178 for (uint8_t k = 16; k < 64; k++)
123 { // Remaining 48 blocks
124 8010 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 10675 times.
✓ Branch 1 taken 168 times.
10843 for (uint8_t i = 0; i < 64; i++)
133 {
134 10675 maj = SHA256::majority(state[0], state[1], state[2]);
135 10669 xorA = SHA256::rotr(state[0], 2) ^ SHA256::rotr(state[0], 13) ^ SHA256::rotr(state[0], 22);
136
137 10679 ch = choose(state[4], state[5], state[6]);
138
139 10674 xorE = SHA256::rotr(state[4], 6) ^ SHA256::rotr(state[4], 11) ^ SHA256::rotr(state[4], 25);
140
141 10656 sum = m[i] + K[i] + state[7] + ch + xorE; // NOLINT
142 10675 newA = xorA + maj + sum;
143 10675 newE = state[3] + sum;
144
145 10675 state[7] = state[6];
146 10675 state[6] = state[5];
147 10675 state[5] = state[4];
148 10675 state[4] = newE;
149 10675 state[3] = state[2];
150 10675 state[2] = state[1];
151 10675 state[1] = state[0];
152 10675 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 6064 times.
✓ Branch 1 taken 168 times.
6232 while (i < end)
168 {
169 6064 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 5376 times.
✓ Branch 1 taken 672 times.
6048 for (uint8_t j = 0; j < 8; j++)
198 {
199 5376 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