hwaccel_amd64.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // hwaccel_amd64.go - AMD64 optimized routines
  2. //
  3. // To the extent possible under law, Yawning Angel has waived all copyright
  4. // and related or neighboring rights to the software, using the Creative
  5. // Commons "CC0" public domain dedication. See LICENSE or
  6. // <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
  7. // +build amd64,!gccgo,!noasm,go1.10
  8. package morus
  9. import "crypto/subtle"
  10. //go:noescape
  11. func cpuidAmd64(cpuidParams *uint32)
  12. //go:noescape
  13. func xgetbv0Amd64(xcrVec *uint32)
  14. //go:noescape
  15. func aeadEncryptAVX2(c, m, a []byte, nonce, key *byte)
  16. //go:noescape
  17. func aeadDecryptAVX2(m, c, a []byte, nonce, key, tag *byte)
  18. func supportsAVX2() bool {
  19. // https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family
  20. const (
  21. osXsaveBit = 1 << 27
  22. avx2Bit = 1 << 5
  23. )
  24. // Check to see if CPUID actually supports the leaf that indicates AVX2.
  25. // CPUID.(EAX=0H, ECX=0H) >= 7
  26. regs := [4]uint32{0x00}
  27. cpuidAmd64(&regs[0])
  28. if regs[0] < 7 {
  29. return false
  30. }
  31. // Check to see if the OS knows how to save/restore XMM/YMM state.
  32. // CPUID.(EAX=01H, ECX=0H):ECX.OSXSAVE[bit 27]==1
  33. regs = [4]uint32{0x01}
  34. cpuidAmd64(&regs[0])
  35. if regs[2]&osXsaveBit == 0 {
  36. return false
  37. }
  38. xcrRegs := [2]uint32{}
  39. xgetbv0Amd64(&xcrRegs[0])
  40. if xcrRegs[0]&6 != 6 {
  41. return false
  42. }
  43. // Check for AVX2 support.
  44. // CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]==1
  45. regs = [4]uint32{0x07}
  46. cpuidAmd64(&regs[0])
  47. return regs[1]&avx2Bit != 0
  48. }
  49. func aeadEncryptYMM(c, m, a, nonce, key []byte) []byte {
  50. mLen := len(m)
  51. ret, out := sliceForAppend(c, mLen+TagSize)
  52. aeadEncryptAVX2(out, m, a, &nonce[0], &key[0])
  53. return ret
  54. }
  55. func aeadDecryptYMM(m, c, a, nonce, key []byte) ([]byte, bool) {
  56. var tag [TagSize]byte
  57. cLen := len(c)
  58. if cLen < TagSize {
  59. return nil, false
  60. }
  61. mLen := cLen - TagSize
  62. ret, out := sliceForAppend(m, mLen)
  63. aeadDecryptAVX2(out, c[:mLen], a, &nonce[0], &key[0], &tag[0])
  64. srcTag := c[mLen:]
  65. ok := subtle.ConstantTimeCompare(srcTag, tag[:]) == 1
  66. if !ok && mLen > 0 {
  67. // Burn decrypted plaintext on auth failure.
  68. burnBytes(out[:mLen])
  69. ret = nil
  70. }
  71. return ret, ok
  72. }
  73. var implAVX2 = &hwaccelImpl{
  74. name: "AVX2",
  75. aeadEncryptFn: aeadEncryptYMM,
  76. aeadDecryptFn: aeadDecryptYMM,
  77. }
  78. func initHardwareAcceleration() {
  79. if supportsAVX2() {
  80. isHardwareAccelerated = true
  81. hardwareAccelImpl = implAVX2
  82. }
  83. }