LCOV - code coverage report
Current view: top level - src/crypto - muhash.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 214 222 96.4 %
Date: 2022-04-21 14:51:19 Functions: 24 24 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 67 74 90.5 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2017-2021 The Bitcoin Core developers
#       2                 :            : // Distributed under the MIT software license, see the accompanying
#       3                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       4                 :            : 
#       5                 :            : #include <crypto/muhash.h>
#       6                 :            : 
#       7                 :            : #include <crypto/chacha20.h>
#       8                 :            : #include <crypto/common.h>
#       9                 :            : #include <hash.h>
#      10                 :            : 
#      11                 :            : #include <cassert>
#      12                 :            : #include <cstdio>
#      13                 :            : #include <limits>
#      14                 :            : 
#      15                 :            : namespace {
#      16                 :            : 
#      17                 :            : using limb_t = Num3072::limb_t;
#      18                 :            : using double_limb_t = Num3072::double_limb_t;
#      19                 :            : constexpr int LIMB_SIZE = Num3072::LIMB_SIZE;
#      20                 :            : /** 2^3072 - 1103717, the largest 3072-bit safe prime number, is used as the modulus. */
#      21                 :            : constexpr limb_t MAX_PRIME_DIFF = 1103717;
#      22                 :            : 
#      23                 :            : /** Extract the lowest limb of [c0,c1,c2] into n, and left shift the number by 1 limb. */
#      24                 :            : inline void extract3(limb_t& c0, limb_t& c1, limb_t& c2, limb_t& n)
#      25                 :  136120069 : {
#      26                 :  136120069 :     n = c0;
#      27                 :  136120069 :     c0 = c1;
#      28                 :  136120069 :     c1 = c2;
#      29                 :  136120069 :     c2 = 0;
#      30                 :  136120069 : }
#      31                 :            : 
#      32                 :            : /** [c0,c1] = a * b */
#      33                 :            : inline void mul(limb_t& c0, limb_t& c1, const limb_t& a, const limb_t& b)
#      34                 :    1227823 : {
#      35                 :    1227823 :     double_limb_t t = (double_limb_t)a * b;
#      36                 :    1227823 :     c1 = t >> LIMB_SIZE;
#      37                 :    1227823 :     c0 = t;
#      38                 :    1227823 : }
#      39                 :            : 
#      40                 :            : /* [c0,c1,c2] += n * [d0,d1,d2]. c2 is 0 initially */
#      41                 :            : inline void mulnadd3(limb_t& c0, limb_t& c1, limb_t& c2, limb_t& d0, limb_t& d1, limb_t& d2, const limb_t& n)
#      42                 :  133286629 : {
#      43                 :  133286629 :     double_limb_t t = (double_limb_t)d0 * n + c0;
#      44                 :  133286629 :     c0 = t;
#      45                 :  133286629 :     t >>= LIMB_SIZE;
#      46                 :  133286629 :     t += (double_limb_t)d1 * n + c1;
#      47                 :  133286629 :     c1 = t;
#      48                 :  133286629 :     t >>= LIMB_SIZE;
#      49                 :  133286629 :     c2 = t + d2 * n;
#      50                 :  133286629 : }
#      51                 :            : 
#      52                 :            : /* [c0,c1] *= n */
#      53                 :            : inline void muln2(limb_t& c0, limb_t& c1, const limb_t& n)
#      54                 :    2836070 : {
#      55                 :    2836070 :     double_limb_t t = (double_limb_t)c0 * n;
#      56                 :    2836070 :     c0 = t;
#      57                 :    2836070 :     t >>= LIMB_SIZE;
#      58                 :    2836070 :     t += (double_limb_t)c1 * n;
#      59                 :    2836070 :     c1 = t;
#      60                 :    2836070 : }
#      61                 :            : 
#      62                 :            : /** [c0,c1,c2] += a * b */
#      63                 :            : inline void muladd3(limb_t& c0, limb_t& c1, limb_t& c2, const limb_t& a, const limb_t& b)
#      64                 :  193819568 : {
#      65                 :  193819568 :     double_limb_t t = (double_limb_t)a * b;
#      66                 :  193819568 :     limb_t th = t >> LIMB_SIZE;
#      67                 :  193819568 :     limb_t tl = t;
#      68                 :            : 
#      69                 :  193819568 :     c0 += tl;
#      70         [ +  + ]:  193819568 :     th += (c0 < tl) ? 1 : 0;
#      71                 :  193819568 :     c1 += th;
#      72         [ +  + ]:  193819568 :     c2 += (c1 < th) ? 1 : 0;
#      73                 :  193819568 : }
#      74                 :            : 
#      75                 :            : /** [c0,c1,c2] += 2 * a * b */
#      76                 :            : inline void muldbladd3(limb_t& c0, limb_t& c1, limb_t& c2, const limb_t& a, const limb_t& b)
#      77                 : 3166472178 : {
#      78                 : 3166472178 :     double_limb_t t = (double_limb_t)a * b;
#      79                 : 3166472178 :     limb_t th = t >> LIMB_SIZE;
#      80                 : 3166472178 :     limb_t tl = t;
#      81                 :            : 
#      82                 : 3166472178 :     c0 += tl;
#      83         [ +  + ]: 3166472178 :     limb_t tt = th + ((c0 < tl) ? 1 : 0);
#      84                 : 3166472178 :     c1 += tt;
#      85         [ +  + ]: 3166472178 :     c2 += (c1 < tt) ? 1 : 0;
#      86                 : 3166472178 :     c0 += tl;
#      87         [ +  + ]: 3166472178 :     th += (c0 < tl) ? 1 : 0;
#      88                 : 3166472178 :     c1 += th;
#      89         [ +  + ]: 3166472178 :     c2 += (c1 < th) ? 1 : 0;
#      90                 : 3166472178 : }
#      91                 :            : 
#      92                 :            : /**
#      93                 :            :  * Add limb a to [c0,c1]: [c0,c1] += a. Then extract the lowest
#      94                 :            :  * limb of [c0,c1] into n, and left shift the number by 1 limb.
#      95                 :            :  * */
#      96                 :            : inline void addnextract2(limb_t& c0, limb_t& c1, const limb_t& a, limb_t& n)
#      97                 :  136121239 : {
#      98                 :  136121239 :     limb_t c2 = 0;
#      99                 :            : 
#     100                 :            :     // add
#     101                 :  136121239 :     c0 += a;
#     102         [ +  + ]:  136121239 :     if (c0 < a) {
#     103                 :     195524 :         c1 += 1;
#     104                 :            : 
#     105                 :            :         // Handle case when c1 has overflown
#     106         [ -  + ]:     195524 :         if (c1 == 0)
#     107                 :          0 :             c2 = 1;
#     108                 :     195524 :     }
#     109                 :            : 
#     110                 :            :     // extract
#     111                 :  136121239 :     n = c0;
#     112                 :  136121239 :     c0 = c1;
#     113                 :  136121239 :     c1 = c2;
#     114                 :  136121239 : }
#     115                 :            : 
#     116                 :            : /** in_out = in_out^(2^sq) * mul */
#     117                 :            : inline void square_n_mul(Num3072& in_out, const int sq, const Num3072& mul)
#     118                 :      12810 : {
#     119         [ +  + ]:     949769 :     for (int j = 0; j < sq; ++j) in_out.Square();
#     120                 :      12810 :     in_out.Multiply(mul);
#     121                 :      12810 : }
#     122                 :            : 
#     123                 :            : } // namespace
#     124                 :            : 
#     125                 :            : /** Indicates whether d is larger than the modulus. */
#     126                 :            : bool Num3072::IsOverflow() const
#     127                 :    2838805 : {
#     128         [ +  + ]:    2838805 :     if (this->limbs[0] <= std::numeric_limits<limb_t>::max() - MAX_PRIME_DIFF) return false;
#     129         [ +  + ]:       1825 :     for (int i = 1; i < LIMBS; ++i) {
#     130         [ -  + ]:       1786 :         if (this->limbs[i] != std::numeric_limits<limb_t>::max()) return false;
#     131                 :       1786 :     }
#     132                 :         39 :     return true;
#     133                 :         39 : }
#     134                 :            : 
#     135                 :            : void Num3072::FullReduce()
#     136                 :         38 : {
#     137                 :         38 :     limb_t c0 = MAX_PRIME_DIFF;
#     138                 :         38 :     limb_t c1 = 0;
#     139         [ +  + ]:       1862 :     for (int i = 0; i < LIMBS; ++i) {
#     140                 :       1824 :         addnextract2(c0, c1, this->limbs[i], this->limbs[i]);
#     141                 :       1824 :     }
#     142                 :         38 : }
#     143                 :            : 
#     144                 :            : Num3072 Num3072::GetInverse() const
#     145                 :        915 : {
#     146                 :            :     // For fast exponentiation a sliding window exponentiation with repunit
#     147                 :            :     // precomputation is utilized. See "Fast Point Decompression for Standard
#     148                 :            :     // Elliptic Curves" (Brumley, Järvinen, 2008).
#     149                 :            : 
#     150                 :        915 :     Num3072 p[12]; // p[i] = a^(2^(2^i)-1)
#     151                 :        915 :     Num3072 out;
#     152                 :            : 
#     153                 :        915 :     p[0] = *this;
#     154                 :            : 
#     155         [ +  + ]:      10980 :     for (int i = 0; i < 11; ++i) {
#     156                 :      10065 :         p[i + 1] = p[i];
#     157         [ +  + ]:    1883049 :         for (int j = 0; j < (1 << i); ++j) p[i + 1].Square();
#     158                 :      10065 :         p[i + 1].Multiply(p[i]);
#     159                 :      10065 :     }
#     160                 :            : 
#     161                 :        915 :     out = p[11];
#     162                 :            : 
#     163                 :        915 :     square_n_mul(out, 512, p[9]);
#     164                 :        915 :     square_n_mul(out, 256, p[8]);
#     165                 :        915 :     square_n_mul(out, 128, p[7]);
#     166                 :        915 :     square_n_mul(out, 64, p[6]);
#     167                 :        915 :     square_n_mul(out, 32, p[5]);
#     168                 :        915 :     square_n_mul(out, 8, p[3]);
#     169                 :        915 :     square_n_mul(out, 2, p[1]);
#     170                 :        915 :     square_n_mul(out, 1, p[0]);
#     171                 :        915 :     square_n_mul(out, 5, p[2]);
#     172                 :        915 :     square_n_mul(out, 3, p[0]);
#     173                 :        915 :     square_n_mul(out, 2, p[0]);
#     174                 :        915 :     square_n_mul(out, 4, p[0]);
#     175                 :        915 :     square_n_mul(out, 4, p[1]);
#     176                 :        915 :     square_n_mul(out, 3, p[0]);
#     177                 :            : 
#     178                 :        915 :     return out;
#     179                 :        915 : }
#     180                 :            : 
#     181                 :            : void Num3072::Multiply(const Num3072& a)
#     182                 :      26124 : {
#     183                 :      26124 :     limb_t c0 = 0, c1 = 0, c2 = 0;
#     184                 :      26124 :     Num3072 tmp;
#     185                 :            : 
#     186                 :            :     /* Compute limbs 0..N-2 of this*a into tmp, including one reduction. */
#     187         [ +  + ]:    1253945 :     for (int j = 0; j < LIMBS - 1; ++j) {
#     188                 :    1227821 :         limb_t d0 = 0, d1 = 0, d2 = 0;
#     189                 :    1227821 :         mul(d0, d1, this->limbs[1 + j], a.limbs[LIMBS + j - (1 + j)]);
#     190         [ +  + ]:   29467729 :         for (int i = 2 + j; i < LIMBS; ++i) muladd3(d0, d1, d2, this->limbs[i], a.limbs[LIMBS + j - i]);
#     191                 :    1227821 :         mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF);
#     192         [ +  + ]:   30695519 :         for (int i = 0; i < j + 1; ++i) muladd3(c0, c1, c2, this->limbs[i], a.limbs[j - i]);
#     193                 :    1227821 :         extract3(c0, c1, c2, tmp.limbs[j]);
#     194                 :    1227821 :     }
#     195                 :            : 
#     196                 :            :     /* Compute limb N-1 of a*b into tmp. */
#     197                 :      26124 :     assert(c2 == 0);
#     198         [ +  + ]:    1280076 :     for (int i = 0; i < LIMBS; ++i) muladd3(c0, c1, c2, this->limbs[i], a.limbs[LIMBS - 1 - i]);
#     199                 :      26124 :     extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]);
#     200                 :            : 
#     201                 :            :     /* Perform a second reduction. */
#     202                 :      26124 :     muln2(c0, c1, MAX_PRIME_DIFF);
#     203         [ +  + ]:    1280076 :     for (int j = 0; j < LIMBS; ++j) {
#     204                 :    1253952 :         addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]);
#     205                 :    1253952 :     }
#     206                 :            : 
#     207                 :      26124 :     assert(c1 == 0);
#     208                 :          0 :     assert(c0 == 0 || c0 == 1);
#     209                 :            : 
#     210                 :            :     /* Perform up to two more reductions if the internal state has already
#     211                 :            :      * overflown the MAX of Num3072 or if it is larger than the modulus or
#     212                 :            :      * if both are the case.
#     213                 :            :      * */
#     214         [ +  + ]:      26124 :     if (this->IsOverflow()) this->FullReduce();
#     215         [ -  + ]:      26124 :     if (c0) this->FullReduce();
#     216                 :      26124 : }
#     217                 :            : 
#     218                 :            : void Num3072::Square()
#     219                 :    2809933 : {
#     220                 :    2809933 :     limb_t c0 = 0, c1 = 0, c2 = 0;
#     221                 :    2809933 :     Num3072 tmp;
#     222                 :            : 
#     223                 :            :     /* Compute limbs 0..N-2 of this*this into tmp, including one reduction. */
#     224         [ +  + ]:  134867854 :     for (int j = 0; j < LIMBS - 1; ++j) {
#     225                 :  132057921 :         limb_t d0 = 0, d1 = 0, d2 = 0;
#     226         [ +  + ]: 1682329182 :         for (int i = 0; i < (LIMBS - 1 - j) / 2; ++i) muldbladd3(d0, d1, d2, this->limbs[i + j + 1], this->limbs[LIMBS - 1 - i]);
#     227         [ +  + ]:  132057921 :         if ((j + 1) & 1) muladd3(d0, d1, d2, this->limbs[(LIMBS - 1 - j) / 2 + j + 1], this->limbs[LIMBS - 1 - (LIMBS - 1 - j) / 2]);
#     228                 :  132057921 :         mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF);
#     229         [ +  + ]: 1682340487 :         for (int i = 0; i < (j + 1) / 2; ++i) muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[j - i]);
#     230         [ +  + ]:  132057921 :         if ((j + 1) & 1) muladd3(c0, c1, c2, this->limbs[(j + 1) / 2], this->limbs[j - (j + 1) / 2]);
#     231                 :  132057921 :         extract3(c0, c1, c2, tmp.limbs[j]);
#     232                 :  132057921 :     }
#     233                 :            : 
#     234                 :    2809933 :     assert(c2 == 0);
#     235         [ +  + ]:   70243883 :     for (int i = 0; i < LIMBS / 2; ++i) muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[LIMBS - 1 - i]);
#     236                 :    2809933 :     extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]);
#     237                 :            : 
#     238                 :            :     /* Perform a second reduction. */
#     239                 :    2809933 :     muln2(c0, c1, MAX_PRIME_DIFF);
#     240         [ +  + ]:  137675637 :     for (int j = 0; j < LIMBS; ++j) {
#     241                 :  134865704 :         addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]);
#     242                 :  134865704 :     }
#     243                 :            : 
#     244                 :    2809933 :     assert(c1 == 0);
#     245                 :          0 :     assert(c0 == 0 || c0 == 1);
#     246                 :            : 
#     247                 :            :     /* Perform up to two more reductions if the internal state has already
#     248                 :            :      * overflown the MAX of Num3072 or if it is larger than the modulus or
#     249                 :            :      * if both are the case.
#     250                 :            :      * */
#     251         [ -  + ]:    2809933 :     if (this->IsOverflow()) this->FullReduce();
#     252         [ -  + ]:    2809933 :     if (c0) this->FullReduce();
#     253                 :    2809933 : }
#     254                 :            : 
#     255                 :            : void Num3072::SetToOne()
#     256                 :    2850880 : {
#     257                 :    2850880 :     this->limbs[0] = 1;
#     258         [ +  + ]:  136838457 :     for (int i = 1; i < LIMBS; ++i) this->limbs[i] = 0;
#     259                 :    2850880 : }
#     260                 :            : 
#     261                 :            : void Num3072::Divide(const Num3072& a)
#     262                 :        915 : {
#     263         [ +  + ]:        915 :     if (this->IsOverflow()) this->FullReduce();
#     264                 :            : 
#     265                 :        915 :     Num3072 inv{};
#     266         [ -  + ]:        915 :     if (a.IsOverflow()) {
#     267                 :          0 :         Num3072 b = a;
#     268                 :          0 :         b.FullReduce();
#     269                 :          0 :         inv = b.GetInverse();
#     270                 :        915 :     } else {
#     271                 :        915 :         inv = a.GetInverse();
#     272                 :        915 :     }
#     273                 :            : 
#     274                 :        915 :     this->Multiply(inv);
#     275         [ -  + ]:        915 :     if (this->IsOverflow()) this->FullReduce();
#     276                 :        915 : }
#     277                 :            : 
#     278                 :       1894 : Num3072::Num3072(const unsigned char (&data)[BYTE_SIZE]) {
#     279         [ +  + ]:      92806 :     for (int i = 0; i < LIMBS; ++i) {
#     280                 :      90912 :         if (sizeof(limb_t) == 4) {
#     281                 :          0 :             this->limbs[i] = ReadLE32(data + 4 * i);
#     282                 :      90912 :         } else if (sizeof(limb_t) == 8) {
#     283                 :      90912 :             this->limbs[i] = ReadLE64(data + 8 * i);
#     284                 :      90912 :         }
#     285                 :      90912 :     }
#     286                 :       1894 : }
#     287                 :            : 
#     288                 :        915 : void Num3072::ToBytes(unsigned char (&out)[BYTE_SIZE]) {
#     289         [ +  + ]:      44835 :     for (int i = 0; i < LIMBS; ++i) {
#     290                 :      43920 :         if (sizeof(limb_t) == 4) {
#     291                 :          0 :             WriteLE32(out + i * 4, this->limbs[i]);
#     292                 :      43920 :         } else if (sizeof(limb_t) == 8) {
#     293                 :      43920 :             WriteLE64(out + i * 8, this->limbs[i]);
#     294                 :      43920 :         }
#     295                 :      43920 :     }
#     296                 :        915 : }
#     297                 :            : 
#     298                 :       1894 : Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
#     299                 :       1894 :     unsigned char tmp[Num3072::BYTE_SIZE];
#     300                 :            : 
#     301                 :       1894 :     uint256 hashed_in = (CHashWriter(SER_DISK, 0) << in).GetSHA256();
#     302                 :       1894 :     ChaCha20(hashed_in.data(), hashed_in.size()).Keystream(tmp, Num3072::BYTE_SIZE);
#     303                 :       1894 :     Num3072 out{tmp};
#     304                 :            : 
#     305                 :       1894 :     return out;
#     306                 :       1894 : }
#     307                 :            : 
#     308                 :            : MuHash3072::MuHash3072(Span<const unsigned char> in) noexcept
#     309                 :        372 : {
#     310                 :        372 :     m_numerator = ToNum3072(in);
#     311                 :        372 : }
#     312                 :            : 
#     313                 :            : void MuHash3072::Finalize(uint256& out) noexcept
#     314                 :        915 : {
#     315                 :        915 :     m_numerator.Divide(m_denominator);
#     316                 :        915 :     m_denominator.SetToOne();  // Needed to keep the MuHash object valid
#     317                 :            : 
#     318                 :        915 :     unsigned char data[Num3072::BYTE_SIZE];
#     319                 :        915 :     m_numerator.ToBytes(data);
#     320                 :            : 
#     321                 :        915 :     out = (CHashWriter(SER_DISK, 0) << data).GetSHA256();
#     322                 :        915 : }
#     323                 :            : 
#     324                 :            : MuHash3072& MuHash3072::operator*=(const MuHash3072& mul) noexcept
#     325                 :        232 : {
#     326                 :        232 :     m_numerator.Multiply(mul.m_numerator);
#     327                 :        232 :     m_denominator.Multiply(mul.m_denominator);
#     328                 :        232 :     return *this;
#     329                 :        232 : }
#     330                 :            : 
#     331                 :            : MuHash3072& MuHash3072::operator/=(const MuHash3072& div) noexcept
#     332                 :        174 : {
#     333                 :        174 :     m_numerator.Multiply(div.m_denominator);
#     334                 :        174 :     m_denominator.Multiply(div.m_numerator);
#     335                 :        174 :     return *this;
#     336                 :        174 : }
#     337                 :            : 
#     338                 :       1493 : MuHash3072& MuHash3072::Insert(Span<const unsigned char> in) noexcept {
#     339                 :       1493 :     m_numerator.Multiply(ToNum3072(in));
#     340                 :       1493 :     return *this;
#     341                 :       1493 : }
#     342                 :            : 
#     343                 :         29 : MuHash3072& MuHash3072::Remove(Span<const unsigned char> in) noexcept {
#     344                 :         29 :     m_denominator.Multiply(ToNum3072(in));
#     345                 :         29 :     return *this;
#     346                 :         29 : }

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a