factory.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. //
  2. // Created by Evgeny Sidorov on 12/04/17.
  3. //
  4. #include <library/cpp/digest/argonish/blake2b.h>
  5. #include <library/cpp/digest/argonish/argon2.h>
  6. #include <library/cpp/digest/argonish/internal/proxies/ref/proxy_ref.h>
  7. #if !defined(_arm64_)
  8. #include <library/cpp/digest/argonish/internal/proxies/sse2/proxy_sse2.h>
  9. #include <library/cpp/digest/argonish/internal/proxies/ssse3/proxy_ssse3.h>
  10. #include <library/cpp/digest/argonish/internal/proxies/sse41/proxy_sse41.h>
  11. #include <library/cpp/digest/argonish/internal/proxies/avx2/proxy_avx2.h>
  12. #endif
  13. #include <util/system/cpu_id.h>
  14. #include <util/generic/yexception.h>
  15. namespace NArgonish {
  16. static EInstructionSet GetBestSet() {
  17. #if !defined(_arm64_)
  18. if (NX86::HaveAVX2()) {
  19. return EInstructionSet::AVX2;
  20. }
  21. if (NX86::HaveSSE41()) {
  22. return EInstructionSet::SSE41;
  23. }
  24. if (NX86::HaveSSSE3()) {
  25. return EInstructionSet::SSSE3;
  26. }
  27. if (NX86::HaveSSE2()) {
  28. return EInstructionSet::SSE2;
  29. }
  30. #endif
  31. return EInstructionSet::REF;
  32. }
  33. TArgon2Factory::TArgon2Factory(bool skipTest) {
  34. InstructionSet_ = GetBestSet();
  35. if (!skipTest)
  36. QuickTest_();
  37. }
  38. THolder<IArgon2Base> TArgon2Factory::Create(EInstructionSet instructionSet, EArgon2Type atype, ui32 tcost,
  39. ui32 mcost, ui32 threads, const ui8* key, ui32 keylen) const {
  40. switch (instructionSet) {
  41. case EInstructionSet::REF:
  42. return MakeHolder<TArgon2ProxyREF>(atype, tcost, mcost, threads, key, keylen);
  43. #if !defined(_arm64_)
  44. case EInstructionSet::SSE2:
  45. return MakeHolder<TArgon2ProxySSE2>(atype, tcost, mcost, threads, key, keylen);
  46. case EInstructionSet::SSSE3:
  47. return MakeHolder<TArgon2ProxySSSE3>(atype, tcost, mcost, threads, key, keylen);
  48. case EInstructionSet::SSE41:
  49. return MakeHolder<TArgon2ProxySSSE3>(atype, tcost, mcost, threads, key, keylen);
  50. case EInstructionSet::AVX2:
  51. return MakeHolder<TArgon2ProxyAVX2>(atype, tcost, mcost, threads, key, keylen);
  52. #endif
  53. }
  54. /* to avoid gcc warning */
  55. ythrow yexception() << "Invalid instruction set value";
  56. }
  57. THolder<IArgon2Base> TArgon2Factory::Create(EArgon2Type atype, ui32 tcost, ui32 mcost, ui32 threads,
  58. const ui8* key, ui32 keylen) const {
  59. return Create(InstructionSet_, atype, tcost, mcost, threads, key, keylen);
  60. }
  61. EInstructionSet TArgon2Factory::GetInstructionSet() const {
  62. return InstructionSet_;
  63. }
  64. void TArgon2Factory::QuickTest_() const {
  65. const ui8 password[8] = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
  66. const ui8 salt[8] = {'s', 'o', 'm', 'e', 's', 'a', 'l', 't'};
  67. const ui8 test_result[][32] = {
  68. {0x2e, 0x2e, 0x5e, 0x05, 0xfe, 0x57, 0xac, 0x2c,
  69. 0xf4, 0x72, 0xec, 0xd0, 0x45, 0xef, 0x68, 0x7e,
  70. 0x56, 0x2a, 0x98, 0x0f, 0xd5, 0x03, 0x39, 0xb3,
  71. 0x89, 0xc8, 0x70, 0xe1, 0x96, 0x2b, 0xbc, 0x45},
  72. {0x95, 0x46, 0x6c, 0xc4, 0xf9, 0x2f, 0x87, 0x49,
  73. 0x54, 0x61, 0x7e, 0xec, 0x0a, 0xa1, 0x19, 0x5d,
  74. 0x22, 0x98, 0x0a, 0xbd, 0x62, 0x5e, 0x5c, 0xac,
  75. 0x44, 0x76, 0x3a, 0xe3, 0xa9, 0xcb, 0x6a, 0xb7},
  76. {0xc8, 0xe9, 0xae, 0xdc, 0x95, 0x6f, 0x6a, 0x7d,
  77. 0xff, 0x0a, 0x4d, 0x42, 0x94, 0x0d, 0xf6, 0x28,
  78. 0x62, 0x3f, 0x32, 0x8e, 0xa1, 0x23, 0x50, 0x05,
  79. 0xab, 0xac, 0x93, 0x3c, 0x57, 0x09, 0x3e, 0x23}};
  80. ui8 hash_result[32] = {0};
  81. for (ui32 atype = (ui32)EArgon2Type::Argon2d; atype <= (ui32)EArgon2Type::Argon2id; ++atype) {
  82. auto argon2d = MakeHolder<TArgon2ProxyREF>((EArgon2Type)atype, 1U, 1024U, 1U);
  83. argon2d->Hash(password, sizeof(password), salt, sizeof(salt), hash_result, sizeof(hash_result));
  84. if (memcmp(test_result[atype], hash_result, sizeof(hash_result)) != 0)
  85. ythrow yexception() << "Argon2: Runtime test failed for reference implementation";
  86. }
  87. #if !defined(_arm64_)
  88. if (InstructionSet_ >= EInstructionSet::SSE2) {
  89. for (ui32 atype = (ui32)EArgon2Type::Argon2d; atype <= (ui32)EArgon2Type::Argon2id; ++atype) {
  90. auto argon2d = MakeHolder<TArgon2ProxySSE2>((EArgon2Type)atype, 1U, 1024U, 1U);
  91. argon2d->Hash(password, sizeof(password), salt, sizeof(salt), hash_result, sizeof(hash_result));
  92. if (memcmp(test_result[atype], hash_result, sizeof(hash_result)) != 0)
  93. ythrow yexception() << "Argon2: Runtime test failed for SSE2 implementation";
  94. }
  95. }
  96. if (InstructionSet_ >= EInstructionSet::SSSE3) {
  97. for (ui32 atype = (ui32)EArgon2Type::Argon2d; atype <= (ui32)EArgon2Type::Argon2id; ++atype) {
  98. auto argon2d = MakeHolder<TArgon2ProxySSSE3>((EArgon2Type)atype, 1U, 1024U, 1U);
  99. argon2d->Hash(password, sizeof(password), salt, sizeof(salt), hash_result, sizeof(hash_result));
  100. if (memcmp(test_result[atype], hash_result, sizeof(hash_result)) != 0)
  101. ythrow yexception() << "Argon2: Runtime test failed for SSSE3 implementation";
  102. }
  103. }
  104. if (InstructionSet_ >= EInstructionSet::SSE41) {
  105. for (ui32 atype = (ui32)EArgon2Type::Argon2d; atype <= (ui32)EArgon2Type::Argon2id; ++atype) {
  106. auto argon2d = MakeHolder<TArgon2ProxySSE41>((EArgon2Type)atype, 1U, 1024U, 1U);
  107. argon2d->Hash(password, sizeof(password), salt, sizeof(salt), hash_result, sizeof(hash_result));
  108. if (memcmp(test_result[atype], hash_result, sizeof(hash_result)) != 0)
  109. ythrow yexception() << "Argon2: Runtime test failed for SSE41 implementation";
  110. }
  111. }
  112. if (InstructionSet_ >= EInstructionSet::AVX2) {
  113. for (ui32 atype = (ui32)EArgon2Type::Argon2d; atype <= (ui32)EArgon2Type::Argon2id; ++atype) {
  114. auto argon2d = MakeHolder<TArgon2ProxyAVX2>((EArgon2Type)atype, 1U, 1024U, 1U);
  115. argon2d->Hash(password, sizeof(password), salt, sizeof(salt), hash_result, sizeof(hash_result));
  116. if (memcmp(test_result[atype], hash_result, sizeof(hash_result)) != 0)
  117. ythrow yexception() << "Argon2: Runtime test failed for AVX2 implementation";
  118. }
  119. }
  120. #endif
  121. }
  122. TBlake2BFactory::TBlake2BFactory(bool skipTest) {
  123. InstructionSet_ = GetBestSet();
  124. if (!skipTest)
  125. QuickTest_();
  126. }
  127. THolder<IBlake2Base> TBlake2BFactory::Create(EInstructionSet instructionSet, size_t outlen, const ui8* key,
  128. size_t keylen) const {
  129. switch (instructionSet) {
  130. case EInstructionSet::REF:
  131. return MakeHolder<TBlake2BProxyREF>(outlen, key, keylen);
  132. #if !defined(_arm64_)
  133. case EInstructionSet::SSE2:
  134. return MakeHolder<TBlake2BProxySSE2>(outlen, key, keylen);
  135. case EInstructionSet::SSSE3:
  136. return MakeHolder<TBlake2BProxySSSE3>(outlen, key, keylen);
  137. case EInstructionSet::SSE41:
  138. return MakeHolder<TBlake2BProxySSE41>(outlen, key, keylen);
  139. case EInstructionSet::AVX2:
  140. return MakeHolder<TBlake2BProxyAVX2>(outlen, key, keylen);
  141. #endif
  142. }
  143. /* to supress gcc warning */
  144. ythrow yexception() << "Invalid instruction set";
  145. }
  146. THolder<IBlake2Base> TBlake2BFactory::Create(size_t outlen, const ui8* key, size_t keylen) const {
  147. return Create(InstructionSet_, outlen, key, keylen);
  148. }
  149. EInstructionSet TBlake2BFactory::GetInstructionSet() const {
  150. return InstructionSet_;
  151. }
  152. void TBlake2BFactory::QuickTest_() const {
  153. const char* test_str = "abc";
  154. const ui8 test_result[] = {
  155. 0xcf, 0x4a, 0xb7, 0x91, 0xc6, 0x2b, 0x8d, 0x2b,
  156. 0x21, 0x09, 0xc9, 0x02, 0x75, 0x28, 0x78, 0x16};
  157. ui8 hash_val[16];
  158. if (InstructionSet_ >= EInstructionSet::REF) {
  159. auto blake2 = MakeHolder<TBlake2BProxyREF>(16U);
  160. blake2->Update(test_str, 3);
  161. blake2->Final(hash_val, 16);
  162. if (memcmp(test_result, hash_val, 16) != 0)
  163. ythrow yexception() << "Blake2B: Runtime test failed for reference implementation";
  164. }
  165. #if !defined(_arm64_)
  166. if (InstructionSet_ >= EInstructionSet::SSE2) {
  167. auto blake2 = MakeHolder<TBlake2BProxySSE2>(16U);
  168. blake2->Update(test_str, 3);
  169. blake2->Final(hash_val, 16);
  170. if (memcmp(test_result, hash_val, 16) != 0)
  171. ythrow yexception() << "Blake2B: Runtime test failed for SSE2 implementation";
  172. }
  173. if (InstructionSet_ >= EInstructionSet::SSSE3) {
  174. auto blake2 = MakeHolder<TBlake2BProxySSSE3>(16U);
  175. blake2->Update(test_str, 3);
  176. blake2->Final(hash_val, 16);
  177. if (memcmp(test_result, hash_val, 16) != 0)
  178. ythrow yexception() << "Blake2B: Runtime test failed for SSSE3 implementation";
  179. }
  180. if (InstructionSet_ >= EInstructionSet::SSE41) {
  181. auto blake2 = MakeHolder<TBlake2BProxySSE41>(16U);
  182. blake2->Update(test_str, 3);
  183. blake2->Final(hash_val, 16);
  184. if (memcmp(test_result, hash_val, 16) != 0)
  185. ythrow yexception() << "Blake2B: Runtime test failed for SSE41 implmenetation";
  186. }
  187. if (InstructionSet_ >= EInstructionSet::AVX2) {
  188. auto blake2 = MakeHolder<TBlake2BProxyAVX2>(16U);
  189. blake2->Update(test_str, 3);
  190. blake2->Final(hash_val, 16);
  191. if (memcmp(test_result, hash_val, 16) != 0)
  192. ythrow yexception() << "Blake2B: Runtime test failed for AVX2 implementation";
  193. }
  194. #endif
  195. }
  196. }