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.
5 // +build go1.7,amd64,!gccgo,!appengine
7 package chacha20poly1305
9 import "encoding/binary"
12 func chacha20Poly1305Open(dst
[]byte, key
[]uint32, src
, ad
[]byte) bool
15 func chacha20Poly1305Seal(dst
[]byte, key
[]uint32, src
, ad
[]byte)
17 // cpuid is implemented in chacha20poly1305_amd64.s.
18 func cpuid(eaxArg
, ecxArg
uint32) (eax
, ebx
, ecx
, edx
uint32)
20 // xgetbv with ecx = 0 is implemented in chacha20poly1305_amd64.s.
21 func xgetbv() (eax
, edx
uint32)
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)
41 _
, _
, ecx1
, _
:= cpuid(1, 0)
43 haveSSSE3
:= isSet(9, ecx1
)
46 haveOSXSAVE
:= isSet(27, ecx1
)
48 osSupportsAVX
:= false
49 // For XGETBV, OSXSAVE bit is required and sufficient.
52 // Check if XMM and YMM registers have OS support.
53 osSupportsAVX
= isSet(1, eax
) && isSet(2, eax
)
55 haveAVX
:= isSet(28, ecx1
) && osSupportsAVX
61 _
, ebx7
, _
, _
:= cpuid(7, 0)
62 haveAVX2
:= isSet(5, ebx7
) && haveAVX
63 haveBMI2
:= isSet(8, ebx7
)
65 useAVX2
= haveAVX2
&& haveBMI2
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
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) {
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])
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])
96 func (c
*chacha20poly1305
) seal(dst
, nonce
, plaintext
, additionalData
[]byte) []byte {
98 return c
.sealGeneric(dst
, nonce
, plaintext
, additionalData
)
102 setupState(&state
, &c
.key
, nonce
)
104 ret
, out
:= sliceForAppend(dst
, len(plaintext
)+16)
105 chacha20Poly1305Seal(out
[:], state
[:], plaintext
, additionalData
)
109 func (c
*chacha20poly1305
) open(dst
, nonce
, ciphertext
, additionalData
[]byte) ([]byte, error
) {
111 return c
.openGeneric(dst
, nonce
, ciphertext
, additionalData
)
115 setupState(&state
, &c
.key
, nonce
)
117 ciphertext
= ciphertext
[:len(ciphertext
)-16]
118 ret
, out
:= sliceForAppend(dst
, len(ciphertext
))
119 if !chacha20Poly1305Open(out
, state
[:], ciphertext
, additionalData
) {