Skip to content

Commit

Permalink
Sha256/Hash.cpp: Implement hash type for SHA256.
Browse files Browse the repository at this point in the history
  • Loading branch information
ZmnSCPxj committed Sep 18, 2020
1 parent 9c1fefc commit 366fc84
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 1 deletion.
10 changes: 9 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ libclboss_la_SOURCES = \
S/Bus.hpp \
S/Detail/Signal.hpp \
S/Detail/SignalBase.hpp \
Sha256/Hash.cpp \
Sha256/Hash.hpp \
Sqlite3.hpp \
Sqlite3/Db.cpp \
Sqlite3/Db.hpp \
Expand All @@ -209,6 +211,12 @@ libclboss_la_SOURCES = \
Util/make_unique.hpp \
Util/stringify.hpp

libclboss_la_LIBADD = \
external/libsodium/src/libsodium/libsodium.la
libclboss_la_CPPFLAGS = \
-I$(top_srcdir)/external/libsodium/src/libsodium/include/ \
-I$(top_srcdir)/external/jsmn

# Externals
SUBDIRS = \
external/libsodium/
Expand All @@ -217,7 +225,6 @@ EXTRA_DIST = \
external/jsmn/jsmn.h

AM_CXXFLAGS = -Wall -Werror $(PTHREAD_CFLAGS) $(libev_CFLAGS) $(SQLITE3_CFLAGS) $(CURL_CFLAGS)
AM_CPPFLAGS = -I $(top_srcdir)/external/jsmn
LDADD = libclboss.la $(PTHREAD_LIBS) $(libev_LIBS) $(SQLITE3_LIBS) $(CURL_LIBS)

ACLOCAL_AMFLAGS = -I m4
Expand Down Expand Up @@ -245,6 +252,7 @@ TESTS = \
tests/ln/test_nodeid \
tests/ln/test_scid \
tests/s/test_bus \
tests/sha256/test_hash \
tests/sqlite3/test_sqlite3 \
tests/stats/test_running_mean
check_PROGRAMS = $(TESTS)
44 changes: 44 additions & 0 deletions Sha256/Hash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include"Sha256/Hash.hpp"
#include"Util/Str.hpp"
#include<sodium/utils.h>
#include<stdexcept>

namespace {

std::uint8_t const zero[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

}

namespace Sha256 {

bool Hash::valid_string(std::string const& s) {
return s.size() == 64 && Util::Str::ishex(s);
}
Hash::Hash(std::string const& s) {
auto bytes = Util::Str::hexread(s);
if (bytes.size() != 32)
throw std::invalid_argument("Hashes must be 32 bytes.");
pimpl = std::make_shared<Impl>();
for (auto i = std::size_t(0); i < 32; ++i)
pimpl->d[i] = bytes[i];
}

Hash::operator std::string() const {
if (!pimpl)
return "0000000000000000000000000000000000000000000000000000000000000000";

return Util::Str::hexdump(pimpl->d, 32);
}
Hash::operator bool() const {
if (!pimpl)
return false;

return 0 != sodium_memcmp(zero, pimpl->d, 32);
}
bool Hash::operator==(Hash const& i) const {
auto a = pimpl ? pimpl->d : zero;
auto b = i.pimpl ? i.pimpl->d : zero;
return 0 == sodium_memcmp(a, b, 32);
}

}
86 changes: 86 additions & 0 deletions Sha256/Hash.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#ifndef SHA256_HASH_HPP
#define SHA256_HASH_HPP

#include<cstdint>
#include<iostream>
#include<memory>
#include<string>
#include<utility>

namespace Sha256 { class Hasher; }

namespace Sha256 {

class Hash {
private:
struct Impl {
std::uint8_t d[32];
};
std::shared_ptr<Impl> pimpl;

explicit
Hash(std::uint8_t d[32]) {
pimpl = std::make_shared<Impl>();
for (auto i = std::size_t(0); i < 32; ++i)
pimpl->d[i] = d[i];
}

friend class Sha256::Hasher;
friend class std::hash<Hash>;

public:
Hash() =default;
Hash(Hash const&) =default;
Hash(Hash&&) =default;
Hash& operator=(Hash const&) =default;
Hash& operator=(Hash&&) =default;
~Hash() =default;

static
bool valid_string(std::string const&);
explicit
Hash(std::string const&);

explicit
operator std::string() const;

explicit
operator bool() const;
bool operator!() const {
return !bool(*this);
}

bool operator==(Hash const&) const;
bool operator!=(Hash const& i) const {
return !(*this == i);
}
};

inline
std::ostream& operator<<(std::ostream& os, Hash const& i) {
return os << std::string(i);
}
inline
std::istream& operator>>(std::istream& is, Hash& i) {
auto s = std::string();
is >> s;
i = Hash(s);
return is;
}

}

/* For use with std::unordered_map. */
namespace std {
template<>
struct hash<::Sha256::Hash> {
std::size_t operator()(::Sha256::Hash const& i) const {
if (!i.pimpl)
return 0;
/* Already a hash, so just read it as-is. */
return *reinterpret_cast<std::size_t*>(i.pimpl->d);
}
};
}

#endif /* !defined(SHA256_HASH_HPP) */
33 changes: 33 additions & 0 deletions tests/sha256/test_hash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#undef NDEBUG
#include"Sha256/Hash.hpp"
#include<assert.h>
#include<unordered_set>

int main() {
auto a = Sha256::Hash();
auto b = Sha256::Hash();
assert(a == b);
b = Sha256::Hash("0123456789012345678901234567890123456789012345678901234567890123");
assert(a != b);
assert(Sha256::Hash::valid_string("0123456789012345678901234567890123456789012345678901234567890123"));

a = Sha256::Hash("3210987654321098765432109876543210987654321098765432109876543210");
assert(a != b);

auto bag = std::unordered_set<Sha256::Hash>();
bag.insert(Sha256::Hash("0123456789012345678901234567890123456789012345678901234567890123"));
assert(bag.find(b) != bag.end());
bag.insert(b);
assert(bag.size() == 1);

assert(std::string(b) == "0123456789012345678901234567890123456789012345678901234567890123");

assert(a);
assert(b);
a = Sha256::Hash();
assert(!a);
b = Sha256::Hash("0000000000000000000000000000000000000000000000000000000000000000");
assert(!b);

return 0;
}

0 comments on commit 366fc84

Please sign in to comment.