Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

87 rader
2.1 KiB

2 år sedan
  1. #pragma once
  2. #include <array>
  3. #include <algorithm>
  4. #include <cstdint>
  5. #define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
  6. #define QR(a, b, c, d) ( \
  7. a += b, d ^= a, d = ROTL(d,16), \
  8. c += d, b ^= c, b = ROTL(b,12), \
  9. a += b, d ^= a, d = ROTL(d, 8), \
  10. c += d, b ^= c, b = ROTL(b, 7))
  11. //
  12. // Based on code from RFC 7539
  13. //
  14. template<int ROUNDS>
  15. void chacha_do_rounds(std::array<uint32_t, 16>& out) {
  16. static_assert(ROUNDS%2 == 0, "ChaPRNG: Rounds count MUST be even.");
  17. for (int i = 0; i < ROUNDS; i += 2) {
  18. // Odd round
  19. QR(out[0], out[4], out[ 8], out[12]); // column 0
  20. QR(out[1], out[5], out[ 9], out[13]); // column 1
  21. QR(out[2], out[6], out[10], out[14]); // column 2
  22. QR(out[3], out[7], out[11], out[15]); // column 3
  23. // Even round
  24. QR(out[0], out[5], out[10], out[15]); // diagonal 1 (main diagonal)
  25. QR(out[1], out[6], out[11], out[12]); // diagonal 2
  26. QR(out[2], out[7], out[ 8], out[13]); // diagonal 3
  27. QR(out[3], out[4], out[ 9], out[14]); // diagonal 4
  28. }
  29. }
  30. template<int ROUNDS, bool REMIX = true, bool DIRECT = false>
  31. std::array<uint32_t, 16> chacha_block(std::array<uint32_t, 16>& in)
  32. {
  33. std::array<uint32_t, 16> out;
  34. int i;
  35. if constexpr(DIRECT) {
  36. chacha_do_rounds<ROUNDS>(in);
  37. return out;
  38. }else {
  39. for (i = 0; i < 16; ++i)
  40. out[i] = in[i];
  41. chacha_do_rounds<ROUNDS>(out);
  42. if constexpr(REMIX) {
  43. for (i = 0; i < 16; ++i)
  44. out[i] += in[i];
  45. }
  46. return out;
  47. }
  48. }
  49. template<int ROUNDS, bool REMIX = true, bool DIRECT = false>
  50. class ChaPRNG {
  51. std::array<uint32_t, 16> source;
  52. std::array<uint32_t, 16> current;
  53. uint32_t it = 0;
  54. public:
  55. ChaPRNG(std::array<uint32_t, 12> seed = {0}) {
  56. source[0] = 'expa';
  57. source[1] = 'nd 3';
  58. source[2] = '2-by';
  59. source[3] = 'te k';
  60. std::copy(seed.begin(), seed.end(), source.begin()+4);
  61. }
  62. uint32_t operator()() {
  63. auto spot = it & 0b1111;
  64. if(spot == 0) {
  65. source[12]++;
  66. if constexpr (DIRECT) {
  67. chacha_block<ROUNDS, REMIX, DIRECT>(source);
  68. } else {
  69. current = chacha_block<ROUNDS, REMIX, DIRECT>(source);
  70. }
  71. }
  72. ++it;
  73. if constexpr (DIRECT)
  74. return source[spot];
  75. else
  76. return current[spot];
  77. }
  78. };