Skip to content

Commit

Permalink
Add Sha256 class. (#135)
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyastolfi authored Nov 30, 2023
1 parent 3fbd411 commit a919642
Show file tree
Hide file tree
Showing 5 changed files with 424 additions and 5 deletions.
10 changes: 5 additions & 5 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,16 @@ def set_version(self):

def requirements(self):
deps = [
"libbacktrace/cci.20210118",
"gtest/1.14.0",
"boost/1.83.0",
"glog/0.6.0",
"batteries/0.49.1",
"boost/1.83.0",
"cli11/2.3.2",
"glog/0.6.0",
"gtest/1.14.0",
"libbacktrace/cci.20210118",
"openssl/3.1.3",
]

override_deps = [
"openssl/3.1.1",
"zlib/1.2.13",
]

Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ macro(LLFS_DefineLibrary TARGET_NAME TARGET_SRCDIR)
GTest::gmock
GTest::gmock_main
libfuse::libfuse
OpenSSL::Crypto
Boost::context
Boost::stacktrace_backtrace
libbacktrace::libbacktrace
Expand Down
75 changes: 75 additions & 0 deletions src/llfs/sha256.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//#=##=##=#==#=#==#===#+==#+==========+==+=+=+=+=+=++=+++=+++++=-++++=-+++++++++++
//
// Part of the LLFS Project, under Apache License v2.0.
// See https://www.apache.org/licenses/LICENSE-2.0 for license information.
// SPDX short identifier: Apache-2.0
//
//+++++++++++-+-+--+----- --- -- - - - -

#include <llfs/sha256.hpp>
//

namespace llfs {

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/*static*/ batt::Optional<Sha256> Sha256::from_str(const std::string_view& s)
{
Sha256 result;

const char* next_ch = s.data();
const char* last_ch = s.data() + s.size();

for (u8& byte : result.bytes) {
byte = 0;
{
if (next_ch == last_ch) {
return batt::None;
}
const char ch = *next_ch;

if ('0' <= ch && ch <= '9') {
byte = (ch - '0') << 4;
} else if ('A' <= ch && ch <= 'F') {
byte = (ch - 'A' + 0xa) << 4;
} else if ('a' <= ch && ch <= 'f') {
byte = (ch - 'a' + 0xa) << 4;
} else {
return batt::None;
}
}
++next_ch;
{
if (next_ch == last_ch) {
return batt::None;
}

const char ch = *next_ch;

if ('0' <= ch && ch <= '9') {
byte |= (ch - '0');
} else if ('A' <= ch && ch <= 'F') {
byte |= (ch - 'A' + 0xa);
} else if ('a' <= ch && ch <= 'f') {
byte |= (ch - 'a' + 0xa);
} else {
return batt::None;
}
}
++next_ch;
}

return result;
}

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
std::ostream& operator<<(std::ostream& out, const Sha256& t)
{
for (u8 next_byte : t.bytes) {
out << batt::to_string(std::hex, std::setw(2), std::setfill('0'), (int)next_byte);
}
return out;
}

} //namespace llfs
166 changes: 166 additions & 0 deletions src/llfs/sha256.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
//#=##=##=#==#=#==#===#+==#+==========+==+=+=+=+=+=++=+++=+++++=-++++=-+++++++++++
//
// Part of the LLFS Project, under Apache License v2.0.
// See https://www.apache.org/licenses/LICENSE-2.0 for license information.
// SPDX short identifier: Apache-2.0
//
//+++++++++++-+-+--+----- --- -- - - - -

#pragma once
#ifndef LLFS_SHA256_HPP
#define LLFS_SHA256_HPP

#include <llfs/config.hpp>
//
#include <llfs/int_types.hpp>
#include <llfs/unpack_cast.hpp>

#include <batteries/buffer.hpp>
#include <batteries/operators.hpp>
#include <batteries/optional.hpp>
#include <batteries/seq.hpp>
#include <batteries/seq/decay.hpp>
#include <batteries/shared_ptr.hpp>
#include <batteries/static_assert.hpp>
#include <batteries/suppress.hpp>
#include <batteries/type_traits.hpp>

#include <boost/container_hash/hash.hpp>

#include <openssl/sha.h>

#include <cstring>

namespace llfs {

//=#=#==#==#===============+=+=+=+=++=++++++++++++++-++-+--+-+----+---------------
//
/** \brief A packable SHA-256 (32-byte) hash.
*/
struct Sha256 {
/** \brief Parses a 64-character hex string and returns the resulting Sha256 value.
*
* \return the parsed Sha256 on success; None if a parsing error occurred.
*/
static batt::Optional<Sha256> from_str(const std::string_view& s);

//+++++++++++-+-+--+----- --- -- - - - -

/** \brief The bytes of the SHA hash.
*/
std::array<u8, SHA256_DIGEST_LENGTH> bytes;

/** \brief Default initializes a Sha256 object; this does NOT set the initial contents of
* `this->bytes`!
*/
Sha256() = default;

//+++++++++++-+-+--+----- --- -- - - - -

/** \brief Returns the raw SHA hash bytes as a binary string; this is NOT the inverse of the
* Sha256::from_str function, but rather just a simple type conversion.
*/
std::string_view as_key() const noexcept
{
return std::string_view{(const char*)bytes.data(), bytes.size()};
}
};

// Sanity check: nothing else but the SHA-256 (256-bits == 32-bytes) in class Sha256!
//
BATT_STATIC_ASSERT_EQ(sizeof(Sha256), 32);

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/** \brief Prints a Sha256 as a hex string; this is the inverse of Sha256::from_str.
*/
std::ostream& operator<<(std::ostream& out, const Sha256& t);

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/** \brief Computes a machine-word-sized hash integer based on the passed Sha256; the returned value
* is suitable for use in containers like std::unordered_map.
*/
inline usize hash_value(const Sha256& sha)
{
usize seed = 0xf345f9e32e60e535ull;
boost::hash_range(seed, sha.bytes.begin(), sha.bytes.end());
return seed;
}

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/** \brief Equality-comparison of Sha256 objects.
*/
inline bool operator==(const Sha256& l, const Sha256& r)
{
return !std::memcmp(l.bytes.data(), r.bytes.data(), l.bytes.size());
}

BATT_EQUALITY_COMPARABLE((inline), Sha256, Sha256)

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/** \brief Order-comparison of Sha256 objects. Uses the byte-wise lexicographical ordering given by
* std::memcpy (i.e., binary dictionary order).
*/
inline bool operator<(const Sha256& l, const Sha256& r)
{
return std::memcmp(l.bytes.data(), r.bytes.data(), l.bytes.size()) < 0;
}

BATT_TOTALLY_ORDERED((inline), Sha256, Sha256)

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/** \brief Performs bounds-checking prior to casting a raw pointer to a (packed) Sha256.
*/
inline batt::Status validate_packed_value(const Sha256& packed, const void* buffer_data,
usize buffer_size)
{
BATT_REQUIRE_OK(llfs::validate_packed_struct(packed, buffer_data, buffer_size));

return batt::OkStatus();
}

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
BATT_SUPPRESS_IF_GCC("-Wdeprecated-declarations")

/** \brief Computes and returns the SHA-256 hash of the data contained in the passed Seq of
* ConstBuffer.
*/
template <typename ConstBufferSeq,
typename = std::enable_if_t<!std::is_convertible_v<ConstBufferSeq&&, batt::ConstBuffer>>>
Sha256 compute_sha256(ConstBufferSeq&& buffers)
{
Sha256 hash;
SHA256_CTX ctx;

SHA256_Init(&ctx);

for (;;) {
batt::Optional<batt::ConstBuffer> buffer = buffers.next();
if (!buffer) {
break;
}
SHA256_Update(&ctx, buffer->data(), buffer->size());
}

SHA256_Final(hash.bytes.data(), &ctx);
return hash;
}

/** \brief Computes and returns the SHA-256 hash of the data contained in the passed buffer.
*/
inline Sha256 compute_sha256(const batt::ConstBuffer& single_buffer)
{
return compute_sha256(batt::seq::single_item(single_buffer) //
| batt::seq::decayed());
}

BATT_UNSUPPRESS_IF_GCC()

} // namespace llfs

#endif // LLFS_SHA256_HPP
Loading

0 comments on commit a919642

Please sign in to comment.