LCOV - code coverage report
Current view: top level - src/crypto - muhash.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 201 206 97.6 %
Date: 2026-06-25 07:23:43 Functions: 26 26 100.0 %

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

Generated by: LCOV version 1.16