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