LCOV - code coverage report
Current view: top level - src/jamidht/eth/libdevcore - FixedHash.h (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 65.0 % 60 39
Test Date: 2026-06-13 09:18:46 Functions: 81.2 % 32 26

            Line data    Source code
       1              : /*
       2              :     This file is part of cpp-ethereum.
       3              : 
       4              :     cpp-ethereum is free software: you can redistribute it and/or modify
       5              :     it under the terms of the GNU General Public License as published by
       6              :     the Free Software Foundation, either version 3 of the License, or
       7              :     (at your option) any later version.
       8              : 
       9              :     cpp-ethereum is distributed in the hope that it will be useful,
      10              :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12              :     GNU General Public License for more details.
      13              : 
      14              :     You should have received a copy of the GNU General Public License
      15              :     along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
      16              : */
      17              : /** @file FixedHash.h
      18              :  * @author Gav Wood <i@gavwood.com>
      19              :  * @date 2014
      20              :  *
      21              :  * The FixedHash fixed-size "hash" container type.
      22              :  */
      23              : 
      24              : #pragma once
      25              : 
      26              : #include <array>
      27              : #include <cstdint>
      28              : #include <algorithm>
      29              : #include <random>
      30              : #include <opendht/rng.h>
      31              : 
      32              : #include "CommonData.h"
      33              : 
      34              : namespace dev {
      35              : 
      36              : /// Compile-time calculation of Log2 of constant values.
      37              : template<unsigned N>
      38              : struct StaticLog2
      39              : {
      40              :     enum { result = 1 + StaticLog2<N / 2>::result };
      41              : };
      42              : template<>
      43              : struct StaticLog2<1>
      44              : {
      45              :     enum { result = 0 };
      46              : };
      47              : 
      48              : /// Fixed-size raw-byte array container type, with an API optimised for storing hashes.
      49              : /// Transparently converts to/from the corresponding arithmetic type; this will
      50              : /// assume the data contained in the hash is big-endian.
      51              : template<unsigned N>
      52              : class FixedHash
      53              : {
      54              : public:
      55              :     /// The size of the container.
      56              :     enum { size = N };
      57              : 
      58              :     /// A dummy flag to avoid accidental construction from pointer.
      59              :     enum ConstructFromPointerType { ConstructFromPointer };
      60              : 
      61              :     /// Method to convert from a string.
      62              :     enum ConstructFromStringType { FromHex, FromBinary };
      63              : 
      64              :     /// Method to convert from a string.
      65              :     enum ConstructFromHashType { AlignLeft, AlignRight, FailIfDifferent };
      66              : 
      67              :     /// Construct an empty hash.
      68         5284 :     FixedHash() { m_data.fill(0); }
      69              : 
      70              :     /// Construct from another hash, filling with zeroes or cropping as necessary.
      71              :     template<unsigned M>
      72              :     explicit FixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = AlignLeft)
      73              :     {
      74              :         m_data.fill(0);
      75              :         unsigned c = std::min(M, N);
      76              :         for (unsigned i = 0; i < c; ++i)
      77              :             m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i];
      78              :     }
      79              : 
      80              :     /// Convert from unsigned
      81              :     explicit FixedHash(unsigned _u) { toBigEndian(_u, m_data); }
      82              : 
      83              :     /// Explicitly construct, copying from a byte array.
      84          776 :     explicit FixedHash(bytes const& _b, ConstructFromHashType _t = FailIfDifferent)
      85              :     {
      86          776 :         if (_b.size() == N)
      87         1552 :             memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N));
      88              :         else {
      89            0 :             m_data.fill(0);
      90            0 :             if (_t != FailIfDifferent) {
      91            0 :                 auto c = std::min<unsigned>(_b.size(), N);
      92            0 :                 for (unsigned i = 0; i < c; ++i)
      93            0 :                     m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i];
      94              :             }
      95              :         }
      96          776 :     }
      97              : 
      98              :     /// Explicitly construct, copying from a byte array.
      99              :     explicit FixedHash(bytesConstRef _b, ConstructFromHashType _t = FailIfDifferent)
     100              :     {
     101              :         if (_b.size() == N)
     102              :             memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N));
     103              :         else {
     104              :             m_data.fill(0);
     105              :             if (_t != FailIfDifferent) {
     106              :                 auto c = std::min<unsigned>(_b.size(), N);
     107              :                 for (unsigned i = 0; i < c; ++i)
     108              :                     m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i];
     109              :             }
     110              :         }
     111              :     }
     112              : 
     113              :     /// Explicitly construct, copying from a bytes in memory with given pointer.
     114         1505 :     explicit FixedHash(uint8_t const* _bs, ConstructFromPointerType) { memcpy(m_data.data(), _bs, N); }
     115              : 
     116              :     /// Explicitly construct, copying from a  string.
     117            0 :     explicit FixedHash(std::string const& _s,
     118              :                        ConstructFromStringType _t = FromHex,
     119              :                        ConstructFromHashType _ht = FailIfDifferent)
     120            0 :         : FixedHash(_t == FromHex ? fromHex(_s, WhenError::Throw) : dev::asBytes(_s), _ht)
     121            0 :     {}
     122              : 
     123              :     /// @returns true iff this is the empty hash.
     124         2234 :     explicit operator bool() const
     125              :     {
     126         4478 :         return std::any_of(m_data.begin(), m_data.end(), [](uint8_t _b) { return _b != 0; });
     127              :     }
     128              : 
     129              :     // The obvious comparison operators.
     130              :     bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
     131              :     bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; }
     132            0 :     bool operator<(FixedHash const& _c) const
     133              :     {
     134            0 :         for (unsigned i = 0; i < N; ++i)
     135            0 :             if (m_data[i] < _c.m_data[i])
     136            0 :                 return true;
     137            0 :             else if (m_data[i] > _c.m_data[i])
     138            0 :                 return false;
     139            0 :         return false;
     140              :     }
     141              :     bool operator>=(FixedHash const& _c) const { return !operator<(_c); }
     142            0 :     bool operator<=(FixedHash const& _c) const { return operator==(_c) || operator<(_c); }
     143            0 :     bool operator>(FixedHash const& _c) const { return !operator<=(_c); }
     144              : 
     145              :     // The obvious binary operators.
     146              :     FixedHash& operator^=(FixedHash const& _c)
     147              :     {
     148              :         for (unsigned i = 0; i < N; ++i)
     149              :             m_data[i] ^= _c.m_data[i];
     150              :         return *this;
     151              :     }
     152              :     FixedHash operator^(FixedHash const& _c) const { return FixedHash(*this) ^= _c; }
     153              :     FixedHash& operator|=(FixedHash const& _c)
     154              :     {
     155              :         for (unsigned i = 0; i < N; ++i)
     156              :             m_data[i] |= _c.m_data[i];
     157              :         return *this;
     158              :     }
     159              :     FixedHash operator|(FixedHash const& _c) const { return FixedHash(*this) |= _c; }
     160              :     FixedHash& operator&=(FixedHash const& _c)
     161              :     {
     162              :         for (unsigned i = 0; i < N; ++i)
     163              :             m_data[i] &= _c.m_data[i];
     164              :         return *this;
     165              :     }
     166              :     FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; }
     167              :     FixedHash operator~() const
     168              :     {
     169              :         FixedHash ret;
     170              :         for (unsigned i = 0; i < N; ++i)
     171              :             ret[i] = ~m_data[i];
     172              :         return ret;
     173              :     }
     174              : 
     175              :     // Big-endian increment.
     176              :     FixedHash& operator++()
     177              :     {
     178              :         for (unsigned i = size; i > 0 && !++m_data[--i];) {
     179              :         }
     180              :         return *this;
     181              :     }
     182              : 
     183              :     /// @returns true if all one-bits in @a _c are set in this object.
     184              :     bool contains(FixedHash const& _c) const { return (*this & _c) == _c; }
     185              : 
     186              :     /// @returns a particular byte from the hash.
     187              :     uint8_t& operator[](unsigned _i) { return m_data[_i]; }
     188              :     /// @returns a particular byte from the hash.
     189              :     uint8_t operator[](unsigned _i) const { return m_data[_i]; }
     190              : 
     191              :     /// @returns an abridged version of the hash as a user-readable hex string.
     192              :     std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; }
     193              : 
     194              :     /// @returns a version of the hash as a user-readable hex string that leaves out the middle part.
     195              :     std::string abridgedMiddle() const
     196              :     {
     197              :         return toHex(ref().cropped(0, 4)) + "\342\200\246" + toHex(ref().cropped(N - 4));
     198              :     }
     199              : 
     200              :     /// @returns the hash as a user-readable hex string.
     201          776 :     std::string hex() const { return toHex(ref()); }
     202              : 
     203              :     /// @returns a mutable byte vector_ref to the object's data.
     204         3090 :     bytesRef ref() { return bytesRef(m_data.data(), N); }
     205              : 
     206              :     /// @returns a constant byte vector_ref to the object's data.
     207         6020 :     bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
     208              : 
     209              :     /// @returns a mutable byte pointer to the object's data.
     210         3010 :     uint8_t* data() { return m_data.data(); }
     211              : 
     212              :     /// @returns a constant byte pointer to the object's data.
     213         4468 :     uint8_t const* data() const { return m_data.data(); }
     214              : 
     215              :     /// @returns begin iterator.
     216              :     auto begin() const -> typename std::array<uint8_t, N>::const_iterator { return m_data.begin(); }
     217              : 
     218              :     /// @returns end iterator.
     219              :     auto end() const -> typename std::array<uint8_t, N>::const_iterator { return m_data.end(); }
     220              : 
     221              :     /// @returns a copy of the object's data as a byte vector.
     222         2187 :     bytes asBytes() const { return bytes(data(), data() + N); }
     223              : 
     224              :     /// @returns a mutable reference to the object's data as an STL array.
     225              :     std::array<uint8_t, N>& asArray() { return m_data; }
     226              : 
     227              :     /// @returns a constant reference to the object's data as an STL array.
     228              :     std::array<uint8_t, N> const& asArray() const { return m_data; }
     229              : 
     230              :     /// Populate with random data.
     231              :     template<class Engine>
     232          729 :     void randomize(Engine& _eng)
     233              :     {
     234        24057 :         for (auto& i : m_data)
     235        23328 :             i = (uint8_t) std::uniform_int_distribution<uint16_t>(0, 255)(_eng);
     236          729 :     }
     237              : 
     238              :     /// @returns a random valued object.
     239              :     static FixedHash random()
     240              :     {
     241              :         FixedHash ret;
     242              :         std::random_device rd;
     243              :         ret.randomize(rd);
     244              :         return ret;
     245              :     }
     246              : 
     247              :     template<unsigned P, unsigned M>
     248              :     inline FixedHash& shiftBloom(FixedHash<M> const& _h)
     249              :     {
     250              :         return (*this |= _h.template bloomPart<P, N>());
     251              :     }
     252              : 
     253              :     template<unsigned P, unsigned M>
     254              :     inline bool containsBloom(FixedHash<M> const& _h)
     255              :     {
     256              :         return contains(_h.template bloomPart<P, N>());
     257              :     }
     258              : 
     259              :     template<unsigned P, unsigned M>
     260              :     inline FixedHash<M> bloomPart() const
     261              :     {
     262              :         unsigned const c_bloomBits = M * 8;
     263              :         unsigned const c_mask = c_bloomBits - 1;
     264              :         unsigned const c_bloomBytes = (StaticLog2<c_bloomBits>::result + 7) / 8;
     265              : 
     266              :         static_assert((M & (M - 1)) == 0, "M must be power-of-two");
     267              :         static_assert(P * c_bloomBytes <= N, "out of range");
     268              : 
     269              :         FixedHash<M> ret;
     270              :         uint8_t const* p = data();
     271              :         for (unsigned i = 0; i < P; ++i) {
     272              :             unsigned index = 0;
     273              :             for (unsigned j = 0; j < c_bloomBytes; ++j, ++p)
     274              :                 index = (index << 8) | *p;
     275              :             index &= c_mask;
     276              :             ret[M - 1 - index / 8] |= (1 << (index % 8));
     277              :         }
     278              :         return ret;
     279              :     }
     280              : 
     281              :     /// Returns the index of the first bit set to one, or size() * 8 if no bits are set.
     282              :     inline unsigned firstBitSet() const
     283              :     {
     284              :         unsigned ret = 0;
     285              :         for (auto d : m_data)
     286              :             if (d)
     287              :                 for (;; ++ret, d <<= 1)
     288              :                     if (d & 0x80)
     289              :                         return ret;
     290              :                     else {
     291              :                     }
     292              :             else
     293              :                 ret += 8;
     294              :         return ret;
     295              :     }
     296              : 
     297              :     void clear() { m_data.fill(0); }
     298              : 
     299              : private:
     300              :     std::array<uint8_t, N> m_data; ///< The binary data.
     301              : };
     302              : 
     303              : template<unsigned T>
     304              : class SecureFixedHash : private FixedHash<T>
     305              : {
     306              : public:
     307              :     using ConstructFromHashType = typename FixedHash<T>::ConstructFromHashType;
     308              :     using ConstructFromStringType = typename FixedHash<T>::ConstructFromStringType;
     309              :     using ConstructFromPointerType = typename FixedHash<T>::ConstructFromPointerType;
     310          729 :     SecureFixedHash() = default;
     311          776 :     explicit SecureFixedHash(bytes const& _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent)
     312          776 :         : FixedHash<T>(_b, _t)
     313          776 :     {}
     314              :     explicit SecureFixedHash(bytesConstRef _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent)
     315              :         : FixedHash<T>(_b, _t)
     316              :     {}
     317              :     template<unsigned M>
     318              :     explicit SecureFixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = FixedHash<T>::AlignLeft)
     319              :         : FixedHash<T>(_h, _t)
     320              :     {}
     321         2234 :     SecureFixedHash(SecureFixedHash<T> const& _h)
     322         2234 :         : FixedHash<T>(_h.makeInsecure())
     323         2234 :     {}
     324              :     template<unsigned M>
     325              :     explicit SecureFixedHash(SecureFixedHash<M> const& _h, ConstructFromHashType _t = FixedHash<T>::AlignLeft)
     326              :         : FixedHash<T>(_h.makeInsecure(), _t)
     327              :     {}
     328              :     explicit SecureFixedHash(std::string const& _s,
     329              :                              ConstructFromStringType _t = FixedHash<T>::FromHex,
     330              :                              ConstructFromHashType _ht = FixedHash<T>::FailIfDifferent)
     331              :         : FixedHash<T>(_s, _t, _ht)
     332              :     {}
     333              :     explicit SecureFixedHash(bytes const* _d, ConstructFromPointerType _t)
     334              :         : FixedHash<T>(_d, _t)
     335              :     {}
     336         3739 :     ~SecureFixedHash() { ref().cleanse(); }
     337              : 
     338              :     SecureFixedHash<T>& operator=(SecureFixedHash<T> const& _c)
     339              :     {
     340              :         if (&_c == this)
     341              :             return *this;
     342              :         ref().cleanse();
     343              :         FixedHash<T>::operator=(static_cast<FixedHash<T> const&>(_c));
     344              :         return *this;
     345              :     }
     346              : 
     347              :     using FixedHash<T>::size;
     348              : 
     349         2963 :     FixedHash<T> const& makeInsecure() const { return static_cast<FixedHash<T> const&>(*this); }
     350              :     FixedHash<T>& writable()
     351              :     {
     352              :         clear();
     353              :         return static_cast<FixedHash<T>&>(*this);
     354              :     }
     355              : 
     356              :     using FixedHash<T>::operator bool;
     357              : 
     358              :     // The obvious comparison operators.
     359              :     bool operator==(SecureFixedHash const& _c) const
     360              :     {
     361              :         return static_cast<FixedHash<T> const&>(*this).operator==(static_cast<FixedHash<T> const&>(_c));
     362              :     }
     363              :     bool operator!=(SecureFixedHash const& _c) const
     364              :     {
     365              :         return static_cast<FixedHash<T> const&>(*this).operator!=(static_cast<FixedHash<T> const&>(_c));
     366              :     }
     367              :     bool operator<(SecureFixedHash const& _c) const
     368              :     {
     369              :         return static_cast<FixedHash<T> const&>(*this).operator<(static_cast<FixedHash<T> const&>(_c));
     370              :     }
     371              :     bool operator>=(SecureFixedHash const& _c) const
     372              :     {
     373              :         return static_cast<FixedHash<T> const&>(*this).operator>=(static_cast<FixedHash<T> const&>(_c));
     374              :     }
     375              :     bool operator<=(SecureFixedHash const& _c) const
     376              :     {
     377              :         return static_cast<FixedHash<T> const&>(*this).operator<=(static_cast<FixedHash<T> const&>(_c));
     378              :     }
     379              :     bool operator>(SecureFixedHash const& _c) const
     380              :     {
     381              :         return static_cast<FixedHash<T> const&>(*this).operator>(static_cast<FixedHash<T> const&>(_c));
     382              :     }
     383              : 
     384              :     using FixedHash<T>::operator==;
     385              :     using FixedHash<T>::operator!=;
     386              :     using FixedHash<T>::operator<;
     387              :     using FixedHash<T>::operator>=;
     388              :     using FixedHash<T>::operator<=;
     389              :     using FixedHash<T>::operator>;
     390              : 
     391              :     // The obvious binary operators.
     392              :     SecureFixedHash& operator^=(FixedHash<T> const& _c)
     393              :     {
     394              :         static_cast<FixedHash<T>&>(*this).operator^=(_c);
     395              :         return *this;
     396              :     }
     397              :     SecureFixedHash operator^(FixedHash<T> const& _c) const { return SecureFixedHash(*this) ^= _c; }
     398              :     SecureFixedHash& operator|=(FixedHash<T> const& _c)
     399              :     {
     400              :         static_cast<FixedHash<T>&>(*this).operator^=(_c);
     401              :         return *this;
     402              :     }
     403              :     SecureFixedHash operator|(FixedHash<T> const& _c) const { return SecureFixedHash(*this) |= _c; }
     404              :     SecureFixedHash& operator&=(FixedHash<T> const& _c)
     405              :     {
     406              :         static_cast<FixedHash<T>&>(*this).operator^=(_c);
     407              :         return *this;
     408              :     }
     409              :     SecureFixedHash operator&(FixedHash<T> const& _c) const { return SecureFixedHash(*this) &= _c; }
     410              : 
     411              :     SecureFixedHash& operator^=(SecureFixedHash const& _c)
     412              :     {
     413              :         static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c));
     414              :         return *this;
     415              :     }
     416              :     SecureFixedHash operator^(SecureFixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; }
     417              :     SecureFixedHash& operator|=(SecureFixedHash const& _c)
     418              :     {
     419              :         static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c));
     420              :         return *this;
     421              :     }
     422              :     SecureFixedHash operator|(SecureFixedHash const& _c) const { return SecureFixedHash(*this) |= _c; }
     423              :     SecureFixedHash& operator&=(SecureFixedHash const& _c)
     424              :     {
     425              :         static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c));
     426              :         return *this;
     427              :     }
     428              :     SecureFixedHash operator&(SecureFixedHash const& _c) const { return SecureFixedHash(*this) &= _c; }
     429              :     SecureFixedHash operator~() const
     430              :     {
     431              :         auto r = ~static_cast<FixedHash<T> const&>(*this);
     432              :         return static_cast<SecureFixedHash const&>(r);
     433              :     }
     434              : 
     435              :     using FixedHash<T>::abridged;
     436              :     using FixedHash<T>::abridgedMiddle;
     437              : 
     438         3739 :     bytesConstRef ref() const { return FixedHash<T>::ref(); }
     439         1505 :     uint8_t const* data() const { return FixedHash<T>::data(); }
     440              : 
     441          729 :     static SecureFixedHash<T> random()
     442              :     {
     443          729 :         SecureFixedHash<T> ret;
     444          729 :         std::random_device rd;
     445          729 :         ret.randomize(rd);
     446         1458 :         return ret;
     447          729 :     }
     448              :     using FixedHash<T>::firstBitSet;
     449              : 
     450              :     void clear() { ref().cleanse(); }
     451              : };
     452              : 
     453              : /// Fast equality operator for h256.
     454              : template<>
     455              : inline bool
     456            0 : FixedHash<32>::operator==(FixedHash<32> const& _other) const
     457              : {
     458            0 :     const uint64_t* hash1 = (const uint64_t*) data();
     459            0 :     const uint64_t* hash2 = (const uint64_t*) _other.data();
     460            0 :     return (hash1[0] == hash2[0]) && (hash1[1] == hash2[1]) && (hash1[2] == hash2[2]) && (hash1[3] == hash2[3]);
     461              : }
     462              : 
     463              : // Common types of FixedHash.
     464              : using h2048 = FixedHash<256>;
     465              : using h1024 = FixedHash<128>;
     466              : using h520 = FixedHash<65>;
     467              : using h512 = FixedHash<64>;
     468              : using h256 = FixedHash<32>;
     469              : using h160 = FixedHash<20>;
     470              : using h128 = FixedHash<16>;
     471              : using h64 = FixedHash<8>;
     472              : using h512s = std::vector<h512>;
     473              : using h256s = std::vector<h256>;
     474              : using h160s = std::vector<h160>;
     475              : using h256Set = std::set<h256>;
     476              : using h160Set = std::set<h160>;
     477              : using h256Hash = std::unordered_set<h256>;
     478              : using h160Hash = std::unordered_set<h160>;
     479              : 
     480              : /// Convert the given value into h160 (160-bit unsigned integer) using the right 20 bytes.
     481              : inline h160
     482         1505 : right160(h256 const& _t)
     483              : {
     484         1505 :     h160 ret;
     485         1505 :     memcpy(ret.data(), _t.data() + 12, 20);
     486         1505 :     return ret;
     487              : }
     488              : 
     489              : } // namespace dev
        

Generated by: LCOV version 2.0-1