minisketch.cpp
1 /********************************************************************** 2 * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko * 3 * Distributed under the MIT software license, see the accompanying * 4 * file LICENSE or http://www.opensource.org/licenses/mit-license.php.* 5 **********************************************************************/ 6 7 8 #include <new> 9 10 #define MINISKETCH_BUILD 11 #ifdef _MINISKETCH_H_ 12 # error "minisketch.h cannot be included before minisketch.cpp" 13 #endif 14 #include "../include/minisketch.h" 15 16 #include "false_positives.h" 17 #include "fielddefines.h" 18 #include "sketch.h" 19 20 #ifdef HAVE_CLMUL 21 # ifdef _MSC_VER 22 # include <intrin.h> 23 # else 24 # include <cpuid.h> 25 # endif 26 #endif 27 28 Sketch* ConstructGeneric1Byte(int bits, int implementation); 29 Sketch* ConstructGeneric2Bytes(int bits, int implementation); 30 Sketch* ConstructGeneric3Bytes(int bits, int implementation); 31 Sketch* ConstructGeneric4Bytes(int bits, int implementation); 32 Sketch* ConstructGeneric5Bytes(int bits, int implementation); 33 Sketch* ConstructGeneric6Bytes(int bits, int implementation); 34 Sketch* ConstructGeneric7Bytes(int bits, int implementation); 35 Sketch* ConstructGeneric8Bytes(int bits, int implementation); 36 37 #ifdef HAVE_CLMUL 38 Sketch* ConstructClMul1Byte(int bits, int implementation); 39 Sketch* ConstructClMul2Bytes(int bits, int implementation); 40 Sketch* ConstructClMul3Bytes(int bits, int implementation); 41 Sketch* ConstructClMul4Bytes(int bits, int implementation); 42 Sketch* ConstructClMul5Bytes(int bits, int implementation); 43 Sketch* ConstructClMul6Bytes(int bits, int implementation); 44 Sketch* ConstructClMul7Bytes(int bits, int implementation); 45 Sketch* ConstructClMul8Bytes(int bits, int implementation); 46 Sketch* ConstructClMulTri1Byte(int bits, int implementation); 47 Sketch* ConstructClMulTri2Bytes(int bits, int implementation); 48 Sketch* ConstructClMulTri3Bytes(int bits, int implementation); 49 Sketch* ConstructClMulTri4Bytes(int bits, int implementation); 50 Sketch* ConstructClMulTri5Bytes(int bits, int implementation); 51 Sketch* ConstructClMulTri6Bytes(int bits, int implementation); 52 Sketch* ConstructClMulTri7Bytes(int bits, int implementation); 53 Sketch* ConstructClMulTri8Bytes(int bits, int implementation); 54 #endif 55 56 namespace { 57 58 enum class FieldImpl { 59 GENERIC = 0, 60 #ifdef HAVE_CLMUL 61 CLMUL, 62 CLMUL_TRI, 63 #endif 64 }; 65 66 #ifdef HAVE_CLMUL 67 static inline bool EnableClmul() 68 { 69 #ifdef _MSC_VER 70 int regs[4]; 71 __cpuid(regs, 1); 72 return (regs[2] & 0x2); 73 #else 74 uint32_t eax, ebx, ecx, edx; 75 return (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & 0x2)); 76 #endif 77 } 78 #endif 79 80 Sketch* Construct(int bits, int impl) 81 { 82 switch (FieldImpl(impl)) { 83 case FieldImpl::GENERIC: 84 switch ((bits + 7) / 8) { 85 case 1: 86 return ConstructGeneric1Byte(bits, impl); 87 case 2: 88 return ConstructGeneric2Bytes(bits, impl); 89 case 3: 90 return ConstructGeneric3Bytes(bits, impl); 91 case 4: 92 return ConstructGeneric4Bytes(bits, impl); 93 case 5: 94 return ConstructGeneric5Bytes(bits, impl); 95 case 6: 96 return ConstructGeneric6Bytes(bits, impl); 97 case 7: 98 return ConstructGeneric7Bytes(bits, impl); 99 case 8: 100 return ConstructGeneric8Bytes(bits, impl); 101 default: 102 return nullptr; 103 } 104 break; 105 #ifdef HAVE_CLMUL 106 case FieldImpl::CLMUL: 107 if (EnableClmul()) { 108 switch ((bits + 7) / 8) { 109 case 1: 110 return ConstructClMul1Byte(bits, impl); 111 case 2: 112 return ConstructClMul2Bytes(bits, impl); 113 case 3: 114 return ConstructClMul3Bytes(bits, impl); 115 case 4: 116 return ConstructClMul4Bytes(bits, impl); 117 case 5: 118 return ConstructClMul5Bytes(bits, impl); 119 case 6: 120 return ConstructClMul6Bytes(bits, impl); 121 case 7: 122 return ConstructClMul7Bytes(bits, impl); 123 case 8: 124 return ConstructClMul8Bytes(bits, impl); 125 default: 126 return nullptr; 127 } 128 } 129 break; 130 case FieldImpl::CLMUL_TRI: 131 if (EnableClmul()) { 132 switch ((bits + 7) / 8) { 133 case 1: 134 return ConstructClMulTri1Byte(bits, impl); 135 case 2: 136 return ConstructClMulTri2Bytes(bits, impl); 137 case 3: 138 return ConstructClMulTri3Bytes(bits, impl); 139 case 4: 140 return ConstructClMulTri4Bytes(bits, impl); 141 case 5: 142 return ConstructClMulTri5Bytes(bits, impl); 143 case 6: 144 return ConstructClMulTri6Bytes(bits, impl); 145 case 7: 146 return ConstructClMulTri7Bytes(bits, impl); 147 case 8: 148 return ConstructClMulTri8Bytes(bits, impl); 149 default: 150 return nullptr; 151 } 152 } 153 break; 154 #endif 155 } 156 return nullptr; 157 } 158 159 } 160 161 extern "C" { 162 163 int minisketch_bits_supported(uint32_t bits) { 164 #ifdef ENABLE_FIELD_INT_2 165 if (bits == 2) return true; 166 #endif 167 #ifdef ENABLE_FIELD_INT_3 168 if (bits == 3) return true; 169 #endif 170 #ifdef ENABLE_FIELD_INT_4 171 if (bits == 4) return true; 172 #endif 173 #ifdef ENABLE_FIELD_INT_5 174 if (bits == 5) return true; 175 #endif 176 #ifdef ENABLE_FIELD_INT_6 177 if (bits == 6) return true; 178 #endif 179 #ifdef ENABLE_FIELD_INT_7 180 if (bits == 7) return true; 181 #endif 182 #ifdef ENABLE_FIELD_INT_8 183 if (bits == 8) return true; 184 #endif 185 #ifdef ENABLE_FIELD_INT_9 186 if (bits == 9) return true; 187 #endif 188 #ifdef ENABLE_FIELD_INT_10 189 if (bits == 10) return true; 190 #endif 191 #ifdef ENABLE_FIELD_INT_11 192 if (bits == 11) return true; 193 #endif 194 #ifdef ENABLE_FIELD_INT_12 195 if (bits == 12) return true; 196 #endif 197 #ifdef ENABLE_FIELD_INT_13 198 if (bits == 13) return true; 199 #endif 200 #ifdef ENABLE_FIELD_INT_14 201 if (bits == 14) return true; 202 #endif 203 #ifdef ENABLE_FIELD_INT_15 204 if (bits == 15) return true; 205 #endif 206 #ifdef ENABLE_FIELD_INT_16 207 if (bits == 16) return true; 208 #endif 209 #ifdef ENABLE_FIELD_INT_17 210 if (bits == 17) return true; 211 #endif 212 #ifdef ENABLE_FIELD_INT_18 213 if (bits == 18) return true; 214 #endif 215 #ifdef ENABLE_FIELD_INT_19 216 if (bits == 19) return true; 217 #endif 218 #ifdef ENABLE_FIELD_INT_20 219 if (bits == 20) return true; 220 #endif 221 #ifdef ENABLE_FIELD_INT_21 222 if (bits == 21) return true; 223 #endif 224 #ifdef ENABLE_FIELD_INT_22 225 if (bits == 22) return true; 226 #endif 227 #ifdef ENABLE_FIELD_INT_23 228 if (bits == 23) return true; 229 #endif 230 #ifdef ENABLE_FIELD_INT_24 231 if (bits == 24) return true; 232 #endif 233 #ifdef ENABLE_FIELD_INT_25 234 if (bits == 25) return true; 235 #endif 236 #ifdef ENABLE_FIELD_INT_26 237 if (bits == 26) return true; 238 #endif 239 #ifdef ENABLE_FIELD_INT_27 240 if (bits == 27) return true; 241 #endif 242 #ifdef ENABLE_FIELD_INT_28 243 if (bits == 28) return true; 244 #endif 245 #ifdef ENABLE_FIELD_INT_29 246 if (bits == 29) return true; 247 #endif 248 #ifdef ENABLE_FIELD_INT_30 249 if (bits == 30) return true; 250 #endif 251 #ifdef ENABLE_FIELD_INT_31 252 if (bits == 31) return true; 253 #endif 254 #ifdef ENABLE_FIELD_INT_32 255 if (bits == 32) return true; 256 #endif 257 #ifdef ENABLE_FIELD_INT_33 258 if (bits == 33) return true; 259 #endif 260 #ifdef ENABLE_FIELD_INT_34 261 if (bits == 34) return true; 262 #endif 263 #ifdef ENABLE_FIELD_INT_35 264 if (bits == 35) return true; 265 #endif 266 #ifdef ENABLE_FIELD_INT_36 267 if (bits == 36) return true; 268 #endif 269 #ifdef ENABLE_FIELD_INT_37 270 if (bits == 37) return true; 271 #endif 272 #ifdef ENABLE_FIELD_INT_38 273 if (bits == 38) return true; 274 #endif 275 #ifdef ENABLE_FIELD_INT_39 276 if (bits == 39) return true; 277 #endif 278 #ifdef ENABLE_FIELD_INT_40 279 if (bits == 40) return true; 280 #endif 281 #ifdef ENABLE_FIELD_INT_41 282 if (bits == 41) return true; 283 #endif 284 #ifdef ENABLE_FIELD_INT_42 285 if (bits == 42) return true; 286 #endif 287 #ifdef ENABLE_FIELD_INT_43 288 if (bits == 43) return true; 289 #endif 290 #ifdef ENABLE_FIELD_INT_44 291 if (bits == 44) return true; 292 #endif 293 #ifdef ENABLE_FIELD_INT_45 294 if (bits == 45) return true; 295 #endif 296 #ifdef ENABLE_FIELD_INT_46 297 if (bits == 46) return true; 298 #endif 299 #ifdef ENABLE_FIELD_INT_47 300 if (bits == 47) return true; 301 #endif 302 #ifdef ENABLE_FIELD_INT_48 303 if (bits == 48) return true; 304 #endif 305 #ifdef ENABLE_FIELD_INT_49 306 if (bits == 49) return true; 307 #endif 308 #ifdef ENABLE_FIELD_INT_50 309 if (bits == 50) return true; 310 #endif 311 #ifdef ENABLE_FIELD_INT_51 312 if (bits == 51) return true; 313 #endif 314 #ifdef ENABLE_FIELD_INT_52 315 if (bits == 52) return true; 316 #endif 317 #ifdef ENABLE_FIELD_INT_53 318 if (bits == 53) return true; 319 #endif 320 #ifdef ENABLE_FIELD_INT_54 321 if (bits == 54) return true; 322 #endif 323 #ifdef ENABLE_FIELD_INT_55 324 if (bits == 55) return true; 325 #endif 326 #ifdef ENABLE_FIELD_INT_56 327 if (bits == 56) return true; 328 #endif 329 #ifdef ENABLE_FIELD_INT_57 330 if (bits == 57) return true; 331 #endif 332 #ifdef ENABLE_FIELD_INT_58 333 if (bits == 58) return true; 334 #endif 335 #ifdef ENABLE_FIELD_INT_59 336 if (bits == 59) return true; 337 #endif 338 #ifdef ENABLE_FIELD_INT_60 339 if (bits == 60) return true; 340 #endif 341 #ifdef ENABLE_FIELD_INT_61 342 if (bits == 61) return true; 343 #endif 344 #ifdef ENABLE_FIELD_INT_62 345 if (bits == 62) return true; 346 #endif 347 #ifdef ENABLE_FIELD_INT_63 348 if (bits == 63) return true; 349 #endif 350 #ifdef ENABLE_FIELD_INT_64 351 if (bits == 64) return true; 352 #endif 353 return false; 354 } 355 356 uint32_t minisketch_implementation_max() { 357 uint32_t ret = 0; 358 #ifdef HAVE_CLMUL 359 ret += 2; 360 #endif 361 return ret; 362 } 363 364 int minisketch_implementation_supported(uint32_t bits, uint32_t implementation) { 365 if (!minisketch_bits_supported(bits) || implementation > minisketch_implementation_max()) { 366 return 0; 367 } 368 try { 369 Sketch* sketch = Construct(bits, implementation); 370 if (sketch) { 371 delete sketch; 372 return 1; 373 } 374 } catch (const std::bad_alloc&) {} 375 return 0; 376 } 377 378 minisketch* minisketch_create(uint32_t bits, uint32_t implementation, size_t capacity) { 379 try { 380 Sketch* sketch = Construct(bits, implementation); 381 if (sketch) { 382 try { 383 sketch->Init(capacity); 384 } catch (const std::bad_alloc&) { 385 delete sketch; 386 throw; 387 } 388 sketch->Ready(); 389 } 390 return (minisketch*)sketch; 391 } catch (const std::bad_alloc&) { 392 return nullptr; 393 } 394 } 395 396 uint32_t minisketch_bits(const minisketch* sketch) { 397 const Sketch* s = (const Sketch*)sketch; 398 s->Check(); 399 return s->Bits(); 400 } 401 402 size_t minisketch_capacity(const minisketch* sketch) { 403 const Sketch* s = (const Sketch*)sketch; 404 s->Check(); 405 return s->Syndromes(); 406 } 407 408 uint32_t minisketch_implementation(const minisketch* sketch) { 409 const Sketch* s = (const Sketch*)sketch; 410 s->Check(); 411 return s->Implementation(); 412 } 413 414 minisketch* minisketch_clone(const minisketch* sketch) { 415 const Sketch* s = (const Sketch*)sketch; 416 s->Check(); 417 Sketch* r = (Sketch*) minisketch_create(s->Bits(), s->Implementation(), s->Syndromes()); 418 if (r) { 419 r->Merge(s); 420 } 421 return (minisketch*) r; 422 } 423 424 void minisketch_destroy(minisketch* sketch) { 425 if (sketch) { 426 Sketch* s = (Sketch*)sketch; 427 s->UnReady(); 428 delete s; 429 } 430 } 431 432 size_t minisketch_serialized_size(const minisketch* sketch) { 433 const Sketch* s = (const Sketch*)sketch; 434 s->Check(); 435 size_t bits = s->Bits(); 436 size_t syndromes = s->Syndromes(); 437 return (bits * syndromes + 7) / 8; 438 } 439 440 void minisketch_serialize(const minisketch* sketch, unsigned char* output) { 441 const Sketch* s = (const Sketch*)sketch; 442 s->Check(); 443 s->Serialize(output); 444 } 445 446 void minisketch_deserialize(minisketch* sketch, const unsigned char* input) { 447 Sketch* s = (Sketch*)sketch; 448 s->Check(); 449 s->Deserialize(input); 450 } 451 452 void minisketch_add_uint64(minisketch* sketch, uint64_t element) { 453 Sketch* s = (Sketch*)sketch; 454 s->Check(); 455 s->Add(element); 456 } 457 458 size_t minisketch_merge(minisketch* sketch, const minisketch* other_sketch) { 459 Sketch* s1 = (Sketch*)sketch; 460 const Sketch* s2 = (const Sketch*)other_sketch; 461 s1->Check(); 462 s2->Check(); 463 if (s1->Bits() != s2->Bits()) return 0; 464 if (s1->Implementation() != s2->Implementation()) return 0; 465 return s1->Merge(s2); 466 } 467 468 ssize_t minisketch_decode(const minisketch* sketch, size_t max_elements, uint64_t* output) { 469 const Sketch* s = (const Sketch*)sketch; 470 s->Check(); 471 return s->Decode(static_cast<int>(max_elements), output); 472 } 473 474 void minisketch_set_seed(minisketch* sketch, uint64_t seed) { 475 Sketch* s = (Sketch*)sketch; 476 s->Check(); 477 s->SetSeed(seed); 478 } 479 480 size_t minisketch_compute_capacity(uint32_t bits, size_t max_elements, uint32_t fpbits) { 481 return ComputeCapacity(bits, max_elements, fpbits); 482 } 483 484 size_t minisketch_compute_max_elements(uint32_t bits, size_t capacity, uint32_t fpbits) { 485 return ComputeMaxElements(bits, capacity, fpbits); 486 } 487 488 }