golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build go1.7,amd64,!gccgo,!appengine
     6  
     7  package chacha20poly1305
     8  
     9  import "encoding/binary"
    10  
    11  //go:noescape
    12  func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
    13  
    14  //go:noescape
    15  func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
    16  
    17  // cpuid is implemented in chacha20poly1305_amd64.s.
    18  func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
    19  
    20  // xgetbv with ecx = 0 is implemented in chacha20poly1305_amd64.s.
    21  func xgetbv() (eax, edx uint32)
    22  
    23  var (
    24  	useASM  bool
    25  	useAVX2 bool
    26  )
    27  
    28  func init() {
    29  	detectCpuFeatures()
    30  }
    31  
    32  // detectCpuFeatures is used to detect if cpu instructions
    33  // used by the functions implemented in assembler in
    34  // chacha20poly1305_amd64.s are supported.
    35  func detectCpuFeatures() {
    36  	maxId, _, _, _ := cpuid(0, 0)
    37  	if maxId < 1 {
    38  		return
    39  	}
    40  
    41  	_, _, ecx1, _ := cpuid(1, 0)
    42  
    43  	haveSSSE3 := isSet(9, ecx1)
    44  	useASM = haveSSSE3
    45  
    46  	haveOSXSAVE := isSet(27, ecx1)
    47  
    48  	osSupportsAVX := false
    49  	// For XGETBV, OSXSAVE bit is required and sufficient.
    50  	if haveOSXSAVE {
    51  		eax, _ := xgetbv()
    52  		// Check if XMM and YMM registers have OS support.
    53  		osSupportsAVX = isSet(1, eax) && isSet(2, eax)
    54  	}
    55  	haveAVX := isSet(28, ecx1) && osSupportsAVX
    56  
    57  	if maxId < 7 {
    58  		return
    59  	}
    60  
    61  	_, ebx7, _, _ := cpuid(7, 0)
    62  	haveAVX2 := isSet(5, ebx7) && haveAVX
    63  	haveBMI2 := isSet(8, ebx7)
    64  
    65  	useAVX2 = haveAVX2 && haveBMI2
    66  }
    67  
    68  // isSet checks if bit at bitpos is set in value.
    69  func isSet(bitpos uint, value uint32) bool {
    70  	return value&(1<<bitpos) != 0
    71  }
    72  
    73  // setupState writes a ChaCha20 input matrix to state. See
    74  // https://tools.ietf.org/html/rfc7539#section-2.3.
    75  func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
    76  	state[0] = 0x61707865
    77  	state[1] = 0x3320646e
    78  	state[2] = 0x79622d32
    79  	state[3] = 0x6b206574
    80  
    81  	state[4] = binary.LittleEndian.Uint32(key[:4])
    82  	state[5] = binary.LittleEndian.Uint32(key[4:8])
    83  	state[6] = binary.LittleEndian.Uint32(key[8:12])
    84  	state[7] = binary.LittleEndian.Uint32(key[12:16])
    85  	state[8] = binary.LittleEndian.Uint32(key[16:20])
    86  	state[9] = binary.LittleEndian.Uint32(key[20:24])
    87  	state[10] = binary.LittleEndian.Uint32(key[24:28])
    88  	state[11] = binary.LittleEndian.Uint32(key[28:32])
    89  
    90  	state[12] = 0
    91  	state[13] = binary.LittleEndian.Uint32(nonce[:4])
    92  	state[14] = binary.LittleEndian.Uint32(nonce[4:8])
    93  	state[15] = binary.LittleEndian.Uint32(nonce[8:12])
    94  }
    95  
    96  func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
    97  	if !useASM {
    98  		return c.sealGeneric(dst, nonce, plaintext, additionalData)
    99  	}
   100  
   101  	var state [16]uint32
   102  	setupState(&state, &c.key, nonce)
   103  
   104  	ret, out := sliceForAppend(dst, len(plaintext)+16)
   105  	chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
   106  	return ret
   107  }
   108  
   109  func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
   110  	if !useASM {
   111  		return c.openGeneric(dst, nonce, ciphertext, additionalData)
   112  	}
   113  
   114  	var state [16]uint32
   115  	setupState(&state, &c.key, nonce)
   116  
   117  	ciphertext = ciphertext[:len(ciphertext)-16]
   118  	ret, out := sliceForAppend(dst, len(ciphertext))
   119  	if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
   120  		for i := range out {
   121  			out[i] = 0
   122  		}
   123  		return nil, errOpen
   124  	}
   125  
   126  	return ret, nil
   127  }