Haraka256_X86.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. #if NETCOREAPP3_0_OR_GREATER
  4. using System;
  5. using System.Buffers.Binary;
  6. using System.Runtime.CompilerServices;
  7. using System.Runtime.InteropServices;
  8. using System.Runtime.Intrinsics;
  9. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests
  10. {
  11. using Aes = System.Runtime.Intrinsics.X86.Aes;
  12. using Sse2 = System.Runtime.Intrinsics.X86.Sse2;
  13. public static class Haraka256_X86
  14. {
  15. public static bool IsSupported => Aes.IsSupported;
  16. public static void Hash(ReadOnlySpan<byte> input, Span<byte> output)
  17. {
  18. if (!IsSupported)
  19. throw new PlatformNotSupportedException(nameof(Haraka256_X86));
  20. var s0 = Load128(input[ ..16]);
  21. var s1 = Load128(input[16..32]);
  22. ImplRounds(ref s0, ref s1, Haraka512_X86.DefaultRoundConstants.AsSpan(0, 20));
  23. s0 = Sse2.Xor(s0, Load128(input[ ..16]));
  24. s1 = Sse2.Xor(s1, Load128(input[16..32]));
  25. Store128(s0, output[ ..16]);
  26. Store128(s1, output[16..32]);
  27. }
  28. public static void Hash(ReadOnlySpan<byte> input, Span<byte> output,
  29. ReadOnlySpan<Vector128<byte>> roundConstants)
  30. {
  31. if (!IsSupported)
  32. throw new PlatformNotSupportedException(nameof(Haraka256_X86));
  33. var s0 = Load128(input[ ..16]);
  34. var s1 = Load128(input[16..32]);
  35. ImplRounds(ref s0, ref s1, roundConstants[..20]);
  36. s0 = Sse2.Xor(s0, Load128(input[ ..16]));
  37. s1 = Sse2.Xor(s1, Load128(input[16..32]));
  38. Store128(s0, output[ ..16]);
  39. Store128(s1, output[16..32]);
  40. }
  41. public static void Permute(ReadOnlySpan<byte> input, Span<byte> output)
  42. {
  43. if (!IsSupported)
  44. throw new PlatformNotSupportedException(nameof(Haraka256_X86));
  45. var s0 = Load128(input[ ..16]);
  46. var s1 = Load128(input[16..32]);
  47. ImplRounds(ref s0, ref s1, Haraka512_X86.DefaultRoundConstants.AsSpan(0, 20));
  48. Store128(s0, output[ ..16]);
  49. Store128(s1, output[16..32]);
  50. }
  51. public static void Permute(ReadOnlySpan<byte> input, Span<byte> output,
  52. ReadOnlySpan<Vector128<byte>> roundConstants)
  53. {
  54. if (!IsSupported)
  55. throw new PlatformNotSupportedException(nameof(Haraka256_X86));
  56. var s0 = Load128(input[ ..16]);
  57. var s1 = Load128(input[16..32]);
  58. ImplRounds(ref s0, ref s1, roundConstants[..20]);
  59. Store128(s0, output[ ..16]);
  60. Store128(s1, output[16..32]);
  61. }
  62. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  63. private static void ImplRounds(ref Vector128<byte> s0, ref Vector128<byte> s1, ReadOnlySpan<Vector128<byte>> rc)
  64. {
  65. ImplRound(ref s0, ref s1, rc[ .. 4]);
  66. ImplRound(ref s0, ref s1, rc[ 4.. 8]);
  67. ImplRound(ref s0, ref s1, rc[ 8..12]);
  68. ImplRound(ref s0, ref s1, rc[12..16]);
  69. ImplRound(ref s0, ref s1, rc[16..20]);
  70. }
  71. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  72. private static void ImplRound(ref Vector128<byte> s0, ref Vector128<byte> s1, ReadOnlySpan<Vector128<byte>> rc)
  73. {
  74. ImplAes(ref s0, ref s1, rc[..4]);
  75. ImplMix(ref s0, ref s1);
  76. }
  77. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  78. private static void ImplAes(ref Vector128<byte> s0, ref Vector128<byte> s1, ReadOnlySpan<Vector128<byte>> rc)
  79. {
  80. s0 = Aes.Encrypt(s0, rc[0]);
  81. s1 = Aes.Encrypt(s1, rc[1]);
  82. s0 = Aes.Encrypt(s0, rc[2]);
  83. s1 = Aes.Encrypt(s1, rc[3]);
  84. }
  85. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  86. private static void ImplMix(ref Vector128<byte> s0, ref Vector128<byte> s1)
  87. {
  88. Vector128<uint> t0 = s0.AsUInt32();
  89. Vector128<uint> t1 = s1.AsUInt32();
  90. s0 = Sse2.UnpackLow(t0, t1).AsByte();
  91. s1 = Sse2.UnpackHigh(t0, t1).AsByte();
  92. }
  93. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  94. private static Vector128<byte> Load128(ReadOnlySpan<byte> t)
  95. {
  96. if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
  97. return MemoryMarshal.Read<Vector128<byte>>(t);
  98. return Vector128.Create(
  99. BinaryPrimitives.ReadUInt64LittleEndian(t[..8]),
  100. BinaryPrimitives.ReadUInt64LittleEndian(t[8..])
  101. ).AsByte();
  102. }
  103. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  104. private static void Store128(Vector128<byte> s, Span<byte> t)
  105. {
  106. if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
  107. {
  108. MemoryMarshal.Write(t, ref s);
  109. return;
  110. }
  111. var u = s.AsUInt64();
  112. BinaryPrimitives.WriteUInt64LittleEndian(t[..8], u.GetElement(0));
  113. BinaryPrimitives.WriteUInt64LittleEndian(t[8..], u.GetElement(1));
  114. }
  115. }
  116. }
  117. #endif
  118. #pragma warning restore
  119. #endif