github.com/mad-day/Yawning-crypto@v0.0.0-20190711051033-5a5f8cca32ec/morus/hwaccel_amd64.go (about)

     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  
     8  // +build amd64,!gccgo,!noasm,go1.10
     9  
    10  package morus
    11  
    12  import "crypto/subtle"
    13  
    14  //go:noescape
    15  func cpuidAmd64(cpuidParams *uint32)
    16  
    17  //go:noescape
    18  func xgetbv0Amd64(xcrVec *uint32)
    19  
    20  //go:noescape
    21  func aeadEncryptAVX2(c, m, a []byte, nonce, key *byte)
    22  
    23  //go:noescape
    24  func aeadDecryptAVX2(m, c, a []byte, nonce, key, tag *byte)
    25  
    26  func supportsAVX2() bool {
    27  	// https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family
    28  	const (
    29  		osXsaveBit = 1 << 27
    30  		avx2Bit    = 1 << 5
    31  	)
    32  
    33  	// Check to see if CPUID actually supports the leaf that indicates AVX2.
    34  	// CPUID.(EAX=0H, ECX=0H) >= 7
    35  	regs := [4]uint32{0x00}
    36  	cpuidAmd64(&regs[0])
    37  	if regs[0] < 7 {
    38  		return false
    39  	}
    40  
    41  	// Check to see if the OS knows how to save/restore XMM/YMM state.
    42  	// CPUID.(EAX=01H, ECX=0H):ECX.OSXSAVE[bit 27]==1
    43  	regs = [4]uint32{0x01}
    44  	cpuidAmd64(&regs[0])
    45  	if regs[2]&osXsaveBit == 0 {
    46  		return false
    47  	}
    48  	xcrRegs := [2]uint32{}
    49  	xgetbv0Amd64(&xcrRegs[0])
    50  	if xcrRegs[0]&6 != 6 {
    51  		return false
    52  	}
    53  
    54  	// Check for AVX2 support.
    55  	// CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]==1
    56  	regs = [4]uint32{0x07}
    57  	cpuidAmd64(&regs[0])
    58  	return regs[1]&avx2Bit != 0
    59  }
    60  
    61  func aeadEncryptYMM(c, m, a, nonce, key []byte) []byte {
    62  	mLen := len(m)
    63  	ret, out := sliceForAppend(c, mLen+TagSize)
    64  	aeadEncryptAVX2(out, m, a, &nonce[0], &key[0])
    65  
    66  	return ret
    67  }
    68  
    69  func aeadDecryptYMM(m, c, a, nonce, key []byte) ([]byte, bool) {
    70  	var tag [TagSize]byte
    71  	cLen := len(c)
    72  
    73  	if cLen < TagSize {
    74  		return nil, false
    75  	}
    76  
    77  	mLen := cLen - TagSize
    78  	ret, out := sliceForAppend(m, mLen)
    79  	aeadDecryptAVX2(out, c[:mLen], a, &nonce[0], &key[0], &tag[0])
    80  
    81  	srcTag := c[mLen:]
    82  	ok := subtle.ConstantTimeCompare(srcTag, tag[:]) == 1
    83  	if !ok && mLen > 0 {
    84  		// Burn decrypted plaintext on auth failure.
    85  		burnBytes(out[:mLen])
    86  		ret = nil
    87  	}
    88  
    89  	return ret, ok
    90  }
    91  
    92  var implAVX2 = &hwaccelImpl{
    93  	name:          "AVX2",
    94  	aeadEncryptFn: aeadEncryptYMM,
    95  	aeadDecryptFn: aeadDecryptYMM,
    96  }
    97  
    98  func initHardwareAcceleration() {
    99  	if supportsAVX2() {
   100  		isHardwareAccelerated = true
   101  		hardwareAccelImpl = implAVX2
   102  	}
   103  }