aes_hash.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. Copyright (c) 2019 tevador
  3. This file is part of RandomX.
  4. RandomX is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. RandomX is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with RandomX. If not, see<http://www.gnu.org/licenses/>.
  14. */
  15. #include "soft_aes.h"
  16. /*
  17. Calculate a 512-bit hash of 'input' using 4 lanes of AES.
  18. The input is treated as a set of round keys for the encryption
  19. of the initial state.
  20. 'inputSize' must be a multiple of 64.
  21. For a 2 MiB input, this has the same security as 32768-round
  22. AES encryption.
  23. Hashing throughput: >20 GiB/s per CPU core with hardware AES
  24. */
  25. template<bool softAes>
  26. void hashAes1Rx4(const void *input, size_t inputSize, void *hash) {
  27. const uint8_t* inptr = (uint8_t*)input;
  28. const uint8_t* inputEnd = inptr + inputSize;
  29. rx_vec_i128 state0, state1, state2, state3;
  30. rx_vec_i128 in0, in1, in2, in3;
  31. //intial state
  32. state0 = rx_set_int_vec_i128(0x8d3126fd, 0x1146d167, 0x887af5ab, 0xc4778e00);
  33. state1 = rx_set_int_vec_i128(0x19fe9fa1, 0x58da632b, 0x1b95af89, 0xb834ef4b);
  34. state2 = rx_set_int_vec_i128(0x1bb2cd74, 0xc35ad744, 0xab283a00, 0x7742dd3a);
  35. state3 = rx_set_int_vec_i128(0xbb30a58a, 0x49593c57, 0xdc5d97cc, 0xe18b449a);
  36. //process 64 bytes at a time in 4 lanes
  37. while (inptr < inputEnd) {
  38. in0 = rx_load_vec_i128((rx_vec_i128*)inptr + 0);
  39. in1 = rx_load_vec_i128((rx_vec_i128*)inptr + 1);
  40. in2 = rx_load_vec_i128((rx_vec_i128*)inptr + 2);
  41. in3 = rx_load_vec_i128((rx_vec_i128*)inptr + 3);
  42. state0 = aesenc<softAes>(state0, in0);
  43. state1 = aesdec<softAes>(state1, in1);
  44. state2 = aesenc<softAes>(state2, in2);
  45. state3 = aesdec<softAes>(state3, in3);
  46. inptr += 64;
  47. }
  48. //two extra rounds to achieve full diffusion
  49. rx_vec_i128 xkey0 = rx_set_int_vec_i128(0x83951283, 0xe4c5593d, 0x2a5a929c, 0x11cbf247);
  50. rx_vec_i128 xkey1 = rx_set_int_vec_i128(0xff215bb2, 0xabbc2523, 0x477bef0b, 0xce816c95);
  51. state0 = aesenc<softAes>(state0, xkey0);
  52. state1 = aesdec<softAes>(state1, xkey0);
  53. state2 = aesenc<softAes>(state2, xkey0);
  54. state3 = aesdec<softAes>(state3, xkey0);
  55. state0 = aesenc<softAes>(state0, xkey1);
  56. state1 = aesdec<softAes>(state1, xkey1);
  57. state2 = aesenc<softAes>(state2, xkey1);
  58. state3 = aesdec<softAes>(state3, xkey1);
  59. //output hash
  60. rx_store_vec_i128((rx_vec_i128*)hash + 0, state0);
  61. rx_store_vec_i128((rx_vec_i128*)hash + 1, state1);
  62. rx_store_vec_i128((rx_vec_i128*)hash + 2, state2);
  63. rx_store_vec_i128((rx_vec_i128*)hash + 3, state3);
  64. }
  65. template void hashAes1Rx4<false>(const void *input, size_t inputSize, void *hash);
  66. template void hashAes1Rx4<true>(const void *input, size_t inputSize, void *hash);
  67. /*
  68. Fill 'buffer' with pseudorandom data based on 512-bit 'state'.
  69. The state is encrypted using a single AES round per 16 bytes of output
  70. in 4 lanes.
  71. 'outputSize' must be a multiple of 64.
  72. The modified state is written back to 'state' to allow multiple
  73. calls to this function.
  74. */
  75. template<bool softAes>
  76. void fillAes1Rx4(void *state, size_t outputSize, void *buffer) {
  77. const uint8_t* outptr = (uint8_t*)buffer;
  78. const uint8_t* outputEnd = outptr + outputSize;
  79. rx_vec_i128 state0, state1, state2, state3;
  80. rx_vec_i128 key0, key1, key2, key3;
  81. key0 = rx_set_int_vec_i128(0xdf20a2e3, 0xca329132, 0x454ff6d5, 0x84eeec2d);
  82. key1 = rx_set_int_vec_i128(0x1deb5971, 0xfed0387f, 0xf10fc578, 0x017b63d0);
  83. key2 = rx_set_int_vec_i128(0xdfc926b3, 0xa517ceb4, 0x2f2c70a1, 0x327d7a52);
  84. key3 = rx_set_int_vec_i128(0x341cf31c, 0xa0ece0a9, 0x3d17da5e, 0x5c8d77d3);
  85. state0 = rx_load_vec_i128((rx_vec_i128*)state + 0);
  86. state1 = rx_load_vec_i128((rx_vec_i128*)state + 1);
  87. state2 = rx_load_vec_i128((rx_vec_i128*)state + 2);
  88. state3 = rx_load_vec_i128((rx_vec_i128*)state + 3);
  89. while (outptr < outputEnd) {
  90. state0 = aesdec<softAes>(state0, key0);
  91. state1 = aesenc<softAes>(state1, key1);
  92. state2 = aesdec<softAes>(state2, key2);
  93. state3 = aesenc<softAes>(state3, key3);
  94. rx_store_vec_i128((rx_vec_i128*)outptr + 0, state0);
  95. rx_store_vec_i128((rx_vec_i128*)outptr + 1, state1);
  96. rx_store_vec_i128((rx_vec_i128*)outptr + 2, state2);
  97. rx_store_vec_i128((rx_vec_i128*)outptr + 3, state3);
  98. outptr += 64;
  99. }
  100. rx_store_vec_i128((rx_vec_i128*)state + 0, state0);
  101. rx_store_vec_i128((rx_vec_i128*)state + 1, state1);
  102. rx_store_vec_i128((rx_vec_i128*)state + 2, state2);
  103. rx_store_vec_i128((rx_vec_i128*)state + 3, state3);
  104. }
  105. template void fillAes1Rx4<true>(void *state, size_t outputSize, void *buffer);
  106. template void fillAes1Rx4<false>(void *state, size_t outputSize, void *buffer);