LCOV - code coverage report
Current view: top level - foo/src/jamidht/eth/libdevcore - FixedHash.h (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 39 60 65.0 %
Date: 2025-12-18 10:07:43 Functions: 26 32 81.2 %

          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        5277 :     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         775 :     explicit FixedHash(bytes const& _b, ConstructFromHashType _t = FailIfDifferent)
      85             :     {
      86         775 :         if (_b.size() == N)
      87         775 :             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         775 :     }
      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        1503 :     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        2231 :     explicit operator bool() const
     125             :     {
     126        4474 :         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        1550 :     std::string hex() const { return toHex(ref()); }
     202             : 
     203             :     /// @returns a mutable byte vector_ref to the object's data.
     204        1543 :     bytesRef ref() { return bytesRef(m_data.data(), N); }
     205             : 
     206             :     /// @returns a constant byte vector_ref to the object's data.
     207        6012 :     bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
     208             : 
     209             :     /// @returns a mutable byte pointer to the object's data.
     210        1503 :     uint8_t* data() { return m_data.data(); }
     211             : 
     212             :     /// @returns a constant byte pointer to the object's data.
     213        4462 :     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         728 :     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         728 :     void randomize(Engine& _eng)
     233             :     {
     234       24024 :         for (auto& i : m_data)
     235       23296 :             i = (uint8_t) std::uniform_int_distribution<uint16_t>(0, 255)(_eng);
     236         728 :     }
     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         728 :     SecureFixedHash() = default;
     311         775 :     explicit SecureFixedHash(bytes const& _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent)
     312         775 :         : FixedHash<T>(_b, _t)
     313         775 :     {}
     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        2231 :     SecureFixedHash(SecureFixedHash<T> const& _h)
     322        2231 :         : FixedHash<T>(_h.makeInsecure())
     323        2231 :     {}
     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        3734 :     ~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        2959 :     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        3734 :     bytesConstRef ref() const { return FixedHash<T>::ref(); }
     439        1503 :     uint8_t const* data() const { return FixedHash<T>::data(); }
     440             : 
     441         728 :     static SecureFixedHash<T> random()
     442             :     {
     443         728 :         SecureFixedHash<T> ret;
     444         728 :         std::random_device rd;
     445         728 :         ret.randomize(rd);
     446        1456 :         return ret;
     447         728 :     }
     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        1503 : right160(h256 const& _t)
     483             : {
     484        1503 :     h160 ret;
     485        1503 :     memcpy(ret.data(), _t.data() + 12, 20);
     486        1503 :     return ret;
     487             : }
     488             : 
     489             : } // namespace dev

Generated by: LCOV version 1.14