Arachne 1.0
Arachne - the perpetual stitcher of Wikidata entities.
Loading...
Searching...
No Matches
arachne::crypto::sha256_hasher Class Referencefinal

#include <include/arachne/crypto.hpp>

Public Member Functions

 sha256_hasher () noexcept
void reset () noexcept
void update (std::span< const std::byte > bytes)
void update (std::string_view bytes)
sha256_digest finish ()
std::string finish_hex ()

Private Member Functions

void transform (const std::byte *block) noexcept

Private Attributes

std::array< std::uint32_t, 8 > state_ {}
std::array< std::byte, 64 > buffer_ {}
std::uint64_t bit_count_ = 0
std::size_t buffered_ = 0
bool finished_ = false
sha256_digest digest_ {}

Detailed Description

Incremental SHA-256 calculator.

Definition at line 17 of file crypto.hpp.

Constructor & Destructor Documentation

◆ sha256_hasher()

arachne::crypto::sha256_hasher::sha256_hasher ( )
noexcept

Definition at line 64 of file crypto.cpp.

64{ reset(); }

References reset().

Here is the call graph for this function:

Member Function Documentation

◆ finish()

sha256_digest arachne::crypto::sha256_hasher::finish ( )
nodiscard

Finalize the digest. Repeated calls return the same value.

Definition at line 117 of file crypto.cpp.

117 {
118 if (finished_) {
119 return digest_;
120 }
121
122 const std::uint64_t original_bit_count = bit_count_;
123 buffer_[buffered_++] = std::byte { 0x80 };
124 if (buffered_ > 56U) {
125 std::fill(
126 buffer_.begin() + static_cast<std::ptrdiff_t>(buffered_),
127 buffer_.end(), std::byte { 0 }
128 );
129 transform(buffer_.data());
130 buffered_ = 0;
131 }
132 std::fill(
133 buffer_.begin() + static_cast<std::ptrdiff_t>(buffered_),
134 buffer_.begin() + 56, std::byte { 0 }
135 );
136 for (std::size_t index = 0; index < 8U; ++index) {
137 const unsigned shift = static_cast<unsigned>((7U - index) * 8U);
138 buffer_[56U + index]
139 = static_cast<std::byte>(original_bit_count >> shift);
140 }
141 transform(buffer_.data());
142
143 for (std::size_t index = 0; index < state_.size(); ++index) {
144 store_be32(digest_.data() + index * 4U, state_[index]);
145 }
146 finished_ = true;
147 buffered_ = 0;
148 return digest_;
149}
void transform(const std::byte *block) noexcept
Definition crypto.cpp:153
std::array< std::byte, 64 > buffer_
Definition crypto.hpp:33
std::array< std::uint32_t, 8 > state_
Definition crypto.hpp:32
void store_be32(std::byte *output, const std::uint32_t value) noexcept
Definition crypto.cpp:43

References bit_count_, buffered_, and finished_.

◆ finish_hex()

std::string arachne::crypto::sha256_hasher::finish_hex ( )
nodiscard

◆ reset()

void arachne::crypto::sha256_hasher::reset ( )
noexcept

Definition at line 66 of file crypto.cpp.

66 {
67 state_ = { 0x6a09e667U, 0xbb67ae85U, 0x3c6ef372U, 0xa54ff53aU,
68 0x510e527fU, 0x9b05688cU, 0x1f83d9abU, 0x5be0cd19U };
69 buffer_.fill(std::byte { 0 });
70 digest_.fill(std::byte { 0 });
71 bit_count_ = 0;
72 buffered_ = 0;
73 finished_ = false;
74}

References bit_count_, buffered_, and finished_.

Referenced by sha256_hasher().

Here is the caller graph for this function:

◆ transform()

void arachne::crypto::sha256_hasher::transform ( const std::byte * block)
privatenoexcept

Definition at line 153 of file crypto.cpp.

153 {
154 std::array<std::uint32_t, 64> schedule {};
155 for (std::size_t index = 0; index < 16U; ++index) {
156 schedule[index] = load_be32(block + index * 4U);
157 }
158 for (std::size_t index = 16; index < schedule.size(); ++index) {
159 const std::uint32_t s0 = std::rotr(schedule[index - 15U], 7)
160 ^ std::rotr(schedule[index - 15U], 18)
161 ^ (schedule[index - 15U] >> 3U);
162 const std::uint32_t s1 = std::rotr(schedule[index - 2U], 17)
163 ^ std::rotr(schedule[index - 2U], 19)
164 ^ (schedule[index - 2U] >> 10U);
165 schedule[index]
166 = schedule[index - 16U] + s0 + schedule[index - 7U] + s1;
167 }
168
169 std::uint32_t a = state_[0];
170 std::uint32_t b = state_[1];
171 std::uint32_t c = state_[2];
172 std::uint32_t d = state_[3];
173 std::uint32_t e = state_[4];
174 std::uint32_t f = state_[5];
175 std::uint32_t g = state_[6];
176 std::uint32_t h = state_[7];
177
178 for (std::size_t index = 0; index < schedule.size(); ++index) {
179 const std::uint32_t sum1
180 = std::rotr(e, 6) ^ std::rotr(e, 11) ^ std::rotr(e, 25);
181 const std::uint32_t choose = (e & f) ^ (~e & g);
182 const std::uint32_t temporary1
183 = h + sum1 + choose + round_constants[index] + schedule[index];
184 const std::uint32_t sum0
185 = std::rotr(a, 2) ^ std::rotr(a, 13) ^ std::rotr(a, 22);
186 const std::uint32_t majority = (a & b) ^ (a & c) ^ (b & c);
187 const std::uint32_t temporary2 = sum0 + majority;
188
189 h = g;
190 g = f;
191 f = e;
192 e = d + temporary1;
193 d = c;
194 c = b;
195 b = a;
196 a = temporary1 + temporary2;
197 }
198
199 state_[0] += a;
200 state_[1] += b;
201 state_[2] += c;
202 state_[3] += d;
203 state_[4] += e;
204 state_[5] += f;
205 state_[6] += g;
206 state_[7] += h;
207}
constexpr std::array< std::uint32_t, 64 > round_constants
Definition crypto.cpp:15
std::uint32_t load_be32(const std::byte *bytes) noexcept
Definition crypto.cpp:33

References arachne::crypto::anonymous_namespace{crypto.cpp}::load_be32().

Referenced by update().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update() [1/2]

void arachne::crypto::sha256_hasher::update ( std::span< const std::byte > bytes)

Definition at line 76 of file crypto.cpp.

76 {
77 if (finished_) {
78 throw std::logic_error("cannot update a finalized SHA-256 digest");
79 }
80 constexpr std::uint64_t max_bytes
81 = std::numeric_limits<std::uint64_t>::max() / 8U;
82 if (bytes.size() > max_bytes
83 || static_cast<std::uint64_t>(bytes.size())
84 > max_bytes - bit_count_ / 8U) {
85 throw std::length_error("SHA-256 input exceeds its length encoding");
86 }
87 bit_count_ += static_cast<std::uint64_t>(bytes.size()) * 8U;
88
89 std::size_t offset = 0;
90 if (buffered_ != 0) {
91 const std::size_t copied
92 = std::min(buffer_.size() - buffered_, bytes.size());
93 std::copy_n(bytes.data(), copied, buffer_.data() + buffered_);
94 buffered_ += copied;
95 offset += copied;
96 if (buffered_ == buffer_.size()) {
97 transform(buffer_.data());
98 buffered_ = 0;
99 }
100 }
101
102 while (bytes.size() - offset >= buffer_.size()) {
103 transform(bytes.data() + offset);
104 offset += buffer_.size();
105 }
106
107 if (offset != bytes.size()) {
108 buffered_ = bytes.size() - offset;
109 std::copy_n(bytes.data() + offset, buffered_, buffer_.data());
110 }
111}

References bit_count_, buffered_, finished_, and transform().

Here is the call graph for this function:

◆ update() [2/2]

void arachne::crypto::sha256_hasher::update ( std::string_view bytes)

Definition at line 113 of file crypto.cpp.

113 {
114 update(std::as_bytes(std::span { bytes.data(), bytes.size() }));
115}
void update(std::span< const std::byte > bytes)
Definition crypto.cpp:76

Member Data Documentation

◆ bit_count_

std::uint64_t arachne::crypto::sha256_hasher::bit_count_ = 0
private

Definition at line 34 of file crypto.hpp.

Referenced by finish(), reset(), and update().

◆ buffer_

std::array<std::byte, 64> arachne::crypto::sha256_hasher::buffer_ {}
private

Definition at line 33 of file crypto.hpp.

33{};

◆ buffered_

std::size_t arachne::crypto::sha256_hasher::buffered_ = 0
private

Definition at line 35 of file crypto.hpp.

Referenced by finish(), reset(), and update().

◆ digest_

sha256_digest arachne::crypto::sha256_hasher::digest_ {}
private

Definition at line 37 of file crypto.hpp.

37{};

◆ finished_

bool arachne::crypto::sha256_hasher::finished_ = false
private

Definition at line 36 of file crypto.hpp.

Referenced by finish(), reset(), and update().

◆ state_

std::array<std::uint32_t, 8> arachne::crypto::sha256_hasher::state_ {}
private

Definition at line 32 of file crypto.hpp.

32{};

The documentation for this class was generated from the following files: