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 }