LCOV - code coverage report
Current view: top level - src/crypto - muhash.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 98.0 % 196 192
Test Date: 2024-08-28 05:13:07 Functions: 100.0 % 21 21
Branches: 85.2 % 88 75

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2017-2022 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                 :  1544667648 : inline void extract3(limb_t& c0, limb_t& c1, limb_t& c2, limb_t& n)
      25                 :             : {
      26                 :  1544667648 :     n = c0;
      27                 :  1544667648 :     c0 = c1;
      28                 :  1544667648 :     c1 = c2;
      29                 :  1544667648 :     c2 = 0;
      30                 :             : }
      31                 :             : 
      32                 :             : /** [c0,c1] = a * b */
      33                 :    13258653 : inline void mul(limb_t& c0, limb_t& c1, const limb_t& a, const limb_t& b)
      34                 :             : {
      35                 :    13258653 :     double_limb_t t = (double_limb_t)a * b;
      36                 :    13258653 :     c1 = t >> LIMB_SIZE;
      37                 :    13258653 :     c0 = t;
      38                 :             : }
      39                 :             : 
      40                 :             : /* [c0,c1,c2] += n * [d0,d1,d2]. c2 is 0 initially */
      41                 :  1512487072 : 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                 :             : {
      43                 :  1512487072 :     double_limb_t t = (double_limb_t)d0 * n + c0;
      44                 :  1512487072 :     c0 = t;
      45                 :  1512487072 :     t >>= LIMB_SIZE;
      46                 :  1512487072 :     t += (double_limb_t)d1 * n + c1;
      47                 :  1512487072 :     c1 = t;
      48                 :  1512487072 :     t >>= LIMB_SIZE;
      49                 :  1512487072 :     c2 = t + d2 * n;
      50                 :  1512487072 : }
      51                 :             : 
      52                 :             : /* [c0,c1] *= n */
      53                 :    32180576 : inline void muln2(limb_t& c0, limb_t& c1, const limb_t& n)
      54                 :             : {
      55                 :    32180576 :     double_limb_t t = (double_limb_t)c0 * n;
      56                 :    32180576 :     c0 = t;
      57                 :    32180576 :     t >>= LIMB_SIZE;
      58                 :    32180576 :     t += (double_limb_t)c1 * n;
      59                 :    32180576 :     c1 = t;
      60                 :             : }
      61                 :             : 
      62                 :             : /** [c0,c1,c2] += a * b */
      63                 :  2167824339 : inline void muladd3(limb_t& c0, limb_t& c1, limb_t& c2, const limb_t& a, const limb_t& b)
      64                 :             : {
      65                 :  2167824339 :     double_limb_t t = (double_limb_t)a * b;
      66                 :  2167824339 :     limb_t th = t >> LIMB_SIZE;
      67                 :  2167824339 :     limb_t tl = t;
      68                 :             : 
      69                 :  2167824339 :     c0 += tl;
      70         [ +  + ]:  2167824339 :     th += (c0 < tl) ? 1 : 0;
      71                 :  2167824339 :     c1 += th;
      72         [ +  + ]:  2167824339 :     c2 += (c1 < th) ? 1 : 0;
      73                 :  2167824339 : }
      74                 :             : 
      75                 :             : /** [c0,c1,c2] += 2 * a * b */
      76                 : 35981482056 : inline void muldbladd3(limb_t& c0, limb_t& c1, limb_t& c2, const limb_t& a, const limb_t& b)
      77                 :             : {
      78                 : 35981482056 :     double_limb_t t = (double_limb_t)a * b;
      79                 : 35981482056 :     limb_t th = t >> LIMB_SIZE;
      80                 : 35981482056 :     limb_t tl = t;
      81                 :             : 
      82                 : 35981482056 :     c0 += tl;
      83         [ +  + ]: 35981482056 :     limb_t tt = th + ((c0 < tl) ? 1 : 0);
      84                 : 35981482056 :     c1 += tt;
      85         [ +  + ]: 35981482056 :     c2 += (c1 < tt) ? 1 : 0;
      86                 : 35981482056 :     c0 += tl;
      87         [ +  + ]: 35981482056 :     th += (c0 < tl) ? 1 : 0;
      88                 : 35981482056 :     c1 += th;
      89         [ +  + ]: 35981482056 :     c2 += (c1 < th) ? 1 : 0;
      90                 : 35981482056 : }
      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                 :  1544668176 : inline void addnextract2(limb_t& c0, limb_t& c1, const limb_t& a, limb_t& n)
      97                 :             : {
      98                 :  1544668176 :     limb_t c2 = 0;
      99                 :             : 
     100                 :             :     // add
     101                 :  1544668176 :     c0 += a;
     102         [ +  + ]:  1544668176 :     if (c0 < a) {
     103                 :      397528 :         c1 += 1;
     104                 :             : 
     105                 :             :         // Handle case when c1 has overflown
     106         [ -  + ]:      397528 :         if (c1 == 0)
     107                 :           0 :             c2 = 1;
     108                 :             :     }
     109                 :             : 
     110                 :             :     // extract
     111                 :  1544668176 :     n = c0;
     112                 :  1544668176 :     c0 = c1;
     113                 :  1544668176 :     c1 = c2;
     114                 :  1544668176 : }
     115                 :             : 
     116                 :             : /** in_out = in_out^(2^sq) * mul */
     117                 :      145418 : inline void square_n_mul(Num3072& in_out, const int sq, const Num3072& mul)
     118                 :             : {
     119         [ +  + ]:    10781706 :     for (int j = 0; j < sq; ++j) in_out.Square();
     120                 :      145418 :     in_out.Multiply(mul);
     121                 :      145418 : }
     122                 :             : 
     123                 :             : } // namespace
     124                 :             : 
     125                 :             : /** Indicates whether d is larger than the modulus. */
     126                 :    32211737 : bool Num3072::IsOverflow() const
     127                 :             : {
     128         [ +  + ]:    32211737 :     if (this->limbs[0] <= std::numeric_limits<limb_t>::max() - MAX_PRIME_DIFF) return false;
     129         [ +  + ]:         528 :     for (int i = 1; i < LIMBS; ++i) {
     130         [ +  - ]:         517 :         if (this->limbs[i] != std::numeric_limits<limb_t>::max()) return false;
     131                 :             :     }
     132                 :             :     return true;
     133                 :             : }
     134                 :             : 
     135                 :          11 : void Num3072::FullReduce()
     136                 :             : {
     137                 :          11 :     limb_t c0 = MAX_PRIME_DIFF;
     138                 :          11 :     limb_t c1 = 0;
     139         [ +  + ]:         539 :     for (int i = 0; i < LIMBS; ++i) {
     140                 :         528 :         addnextract2(c0, c1, this->limbs[i], this->limbs[i]);
     141                 :             :     }
     142                 :          11 : }
     143                 :             : 
     144                 :       10387 : Num3072 Num3072::GetInverse() const
     145                 :             : {
     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         [ +  + ]:      135031 :     Num3072 p[12]; // p[i] = a^(2^(2^i)-1)
     151                 :       10387 :     Num3072 out;
     152                 :             : 
     153                 :       10387 :     p[0] = *this;
     154                 :             : 
     155         [ +  + ]:      124644 :     for (int i = 0; i < 11; ++i) {
     156                 :      114257 :         p[i + 1] = p[i];
     157         [ +  + ]:    21376446 :         for (int j = 0; j < (1 << i); ++j) p[i + 1].Square();
     158                 :      114257 :         p[i + 1].Multiply(p[i]);
     159                 :             :     }
     160                 :             : 
     161                 :       10387 :     out = p[11];
     162                 :             : 
     163                 :       10387 :     square_n_mul(out, 512, p[9]);
     164                 :       10387 :     square_n_mul(out, 256, p[8]);
     165                 :       10387 :     square_n_mul(out, 128, p[7]);
     166                 :       10387 :     square_n_mul(out, 64, p[6]);
     167                 :       10387 :     square_n_mul(out, 32, p[5]);
     168                 :       10387 :     square_n_mul(out, 8, p[3]);
     169                 :       10387 :     square_n_mul(out, 2, p[1]);
     170                 :       10387 :     square_n_mul(out, 1, p[0]);
     171                 :       10387 :     square_n_mul(out, 5, p[2]);
     172                 :       10387 :     square_n_mul(out, 3, p[0]);
     173                 :       10387 :     square_n_mul(out, 2, p[0]);
     174                 :       10387 :     square_n_mul(out, 4, p[0]);
     175                 :       10387 :     square_n_mul(out, 4, p[1]);
     176                 :       10387 :     square_n_mul(out, 3, p[0]);
     177                 :             : 
     178                 :       10387 :     return out;
     179                 :             : }
     180                 :             : 
     181                 :      282099 : void Num3072::Multiply(const Num3072& a)
     182                 :             : {
     183                 :      282099 :     limb_t c0 = 0, c1 = 0, c2 = 0;
     184                 :      282099 :     Num3072 tmp;
     185                 :             : 
     186                 :             :     /* Compute limbs 0..N-2 of this*a into tmp, including one reduction. */
     187         [ +  + ]:    13540752 :     for (int j = 0; j < LIMBS - 1; ++j) {
     188                 :    13258653 :         limb_t d0 = 0, d1 = 0, d2 = 0;
     189                 :    13258653 :         mul(d0, d1, this->limbs[1 + j], a.limbs[LIMBS + j - (1 + j)]);
     190         [ +  + ]:   318207672 :         for (int i = 2 + j; i < LIMBS; ++i) muladd3(d0, d1, d2, this->limbs[i], a.limbs[LIMBS + j - i]);
     191                 :    13258653 :         mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF);
     192         [ +  + ]:   331466325 :         for (int i = 0; i < j + 1; ++i) muladd3(c0, c1, c2, this->limbs[i], a.limbs[j - i]);
     193                 :    13258653 :         extract3(c0, c1, c2, tmp.limbs[j]);
     194                 :             :     }
     195                 :             : 
     196                 :             :     /* Compute limb N-1 of a*b into tmp. */
     197         [ +  - ]:      282099 :     assert(c2 == 0);
     198         [ +  + ]:    13822851 :     for (int i = 0; i < LIMBS; ++i) muladd3(c0, c1, c2, this->limbs[i], a.limbs[LIMBS - 1 - i]);
     199                 :      282099 :     extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]);
     200                 :             : 
     201                 :             :     /* Perform a second reduction. */
     202                 :      282099 :     muln2(c0, c1, MAX_PRIME_DIFF);
     203         [ +  + ]:    13822851 :     for (int j = 0; j < LIMBS; ++j) {
     204                 :    13540752 :         addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]);
     205                 :             :     }
     206                 :             : 
     207         [ -  + ]:      282099 :     assert(c1 == 0);
     208         [ -  + ]:      282099 :     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         [ +  + ]:      282099 :     if (this->IsOverflow()) this->FullReduce();
     215         [ -  + ]:      282099 :     if (c0) this->FullReduce();
     216                 :      282099 : }
     217                 :             : 
     218                 :    31898477 : void Num3072::Square()
     219                 :             : {
     220                 :    31898477 :     limb_t c0 = 0, c1 = 0, c2 = 0;
     221                 :    31898477 :     Num3072 tmp;
     222                 :             : 
     223                 :             :     /* Compute limbs 0..N-2 of this*this into tmp, including one reduction. */
     224         [ +  + ]:  1531126896 :     for (int j = 0; j < LIMBS - 1; ++j) {
     225                 :  1499228419 :         limb_t d0 = 0, d1 = 0, d2 = 0;
     226         [ +  + ]: 19107187723 :         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         [ +  + ]:  1499228419 :         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                 :  1499228419 :         mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF);
     229         [ +  + ]: 19107187723 :         for (int i = 0; i < (j + 1) / 2; ++i) muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[j - i]);
     230         [ +  + ]:  1499228419 :         if ((j + 1) & 1) muladd3(c0, c1, c2, this->limbs[(j + 1) / 2], this->limbs[j - (j + 1) / 2]);
     231                 :  1499228419 :         extract3(c0, c1, c2, tmp.limbs[j]);
     232                 :             :     }
     233                 :             : 
     234         [ +  - ]:    31898477 :     assert(c2 == 0);
     235         [ +  + ]:   797461925 :     for (int i = 0; i < LIMBS / 2; ++i) muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[LIMBS - 1 - i]);
     236                 :    31898477 :     extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]);
     237                 :             : 
     238                 :             :     /* Perform a second reduction. */
     239                 :    31898477 :     muln2(c0, c1, MAX_PRIME_DIFF);
     240         [ +  + ]:  1563025373 :     for (int j = 0; j < LIMBS; ++j) {
     241                 :  1531126896 :         addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]);
     242                 :             :     }
     243                 :             : 
     244         [ -  + ]:    31898477 :     assert(c1 == 0);
     245         [ -  + ]:    31898477 :     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         [ -  + ]:    31898477 :     if (this->IsOverflow()) this->FullReduce();
     252         [ -  + ]:    31898477 :     if (c0) this->FullReduce();
     253                 :    31898477 : }
     254                 :             : 
     255                 :    32336969 : void Num3072::SetToOne()
     256                 :             : {
     257                 :    32336969 :     this->limbs[0] = 1;
     258         [ +  + ]:  1552174512 :     for (int i = 1; i < LIMBS; ++i) this->limbs[i] = 0;
     259                 :    32336969 : }
     260                 :             : 
     261                 :       10387 : void Num3072::Divide(const Num3072& a)
     262                 :             : {
     263         [ +  + ]:       10387 :     if (this->IsOverflow()) this->FullReduce();
     264                 :             : 
     265                 :       10387 :     Num3072 inv{};
     266         [ -  + ]:       10387 :     if (a.IsOverflow()) {
     267                 :           0 :         Num3072 b = a;
     268                 :           0 :         b.FullReduce();
     269                 :           0 :         inv = b.GetInverse();
     270                 :             :     } else {
     271                 :       10387 :         inv = a.GetInverse();
     272                 :             :     }
     273                 :             : 
     274                 :       10387 :     this->Multiply(inv);
     275         [ -  + ]:       10387 :     if (this->IsOverflow()) this->FullReduce();
     276                 :       10387 : }
     277                 :             : 
     278                 :       11817 : Num3072::Num3072(const unsigned char (&data)[BYTE_SIZE]) {
     279         [ +  + ]:      579033 :     for (int i = 0; i < LIMBS; ++i) {
     280                 :      567216 :         if (sizeof(limb_t) == 4) {
     281                 :             :             this->limbs[i] = ReadLE32(data + 4 * i);
     282                 :      567216 :         } else if (sizeof(limb_t) == 8) {
     283                 :      567216 :             this->limbs[i] = ReadLE64(data + 8 * i);
     284                 :             :         }
     285                 :             :     }
     286                 :       11817 : }
     287                 :             : 
     288                 :       10387 : void Num3072::ToBytes(unsigned char (&out)[BYTE_SIZE]) {
     289         [ +  + ]:      508963 :     for (int i = 0; i < LIMBS; ++i) {
     290                 :      498576 :         if (sizeof(limb_t) == 4) {
     291                 :             :             WriteLE32(out + i * 4, this->limbs[i]);
     292                 :      498576 :         } else if (sizeof(limb_t) == 8) {
     293                 :      498576 :             WriteLE64(out + i * 8, this->limbs[i]);
     294                 :             :         }
     295                 :             :     }
     296                 :       10387 : }
     297                 :             : 
     298                 :       11817 : Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
     299                 :       11817 :     unsigned char tmp[Num3072::BYTE_SIZE];
     300                 :             : 
     301                 :       11817 :     uint256 hashed_in{(HashWriter{} << in).GetSHA256()};
     302                 :       11817 :     static_assert(sizeof(tmp) % ChaCha20Aligned::BLOCKLEN == 0);
     303                 :       11817 :     ChaCha20Aligned{MakeByteSpan(hashed_in)}.Keystream(MakeWritableByteSpan(tmp));
     304                 :       11817 :     Num3072 out{tmp};
     305                 :             : 
     306                 :       11817 :     return out;
     307                 :             : }
     308                 :             : 
     309                 :         186 : MuHash3072::MuHash3072(Span<const unsigned char> in) noexcept
     310                 :             : {
     311                 :         186 :     m_numerator = ToNum3072(in);
     312                 :         186 : }
     313                 :             : 
     314                 :       10387 : void MuHash3072::Finalize(uint256& out) noexcept
     315                 :             : {
     316                 :       10387 :     m_numerator.Divide(m_denominator);
     317                 :       10387 :     m_denominator.SetToOne();  // Needed to keep the MuHash object valid
     318                 :             : 
     319                 :       10387 :     unsigned char data[Num3072::BYTE_SIZE];
     320                 :       10387 :     m_numerator.ToBytes(data);
     321                 :             : 
     322                 :       10387 :     out = (HashWriter{} << data).GetSHA256();
     323                 :       10387 : }
     324                 :             : 
     325                 :         120 : MuHash3072& MuHash3072::operator*=(const MuHash3072& mul) noexcept
     326                 :             : {
     327                 :         120 :     m_numerator.Multiply(mul.m_numerator);
     328                 :         120 :     m_denominator.Multiply(mul.m_denominator);
     329                 :         120 :     return *this;
     330                 :             : }
     331                 :             : 
     332                 :          83 : MuHash3072& MuHash3072::operator/=(const MuHash3072& div) noexcept
     333                 :             : {
     334                 :          83 :     m_numerator.Multiply(div.m_denominator);
     335                 :          83 :     m_denominator.Multiply(div.m_numerator);
     336                 :          83 :     return *this;
     337                 :             : }
     338                 :             : 
     339                 :       11419 : MuHash3072& MuHash3072::Insert(Span<const unsigned char> in) noexcept {
     340                 :       11419 :     m_numerator.Multiply(ToNum3072(in));
     341                 :       11419 :     return *this;
     342                 :             : }
     343                 :             : 
     344                 :         212 : MuHash3072& MuHash3072::Remove(Span<const unsigned char> in) noexcept {
     345                 :         212 :     m_denominator.Multiply(ToNum3072(in));
     346                 :         212 :     return *this;
     347                 :             : }
        

Generated by: LCOV version 2.0-1