OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / crypto / chacha20poly1305 / chacha20poly1305_amd64.go
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 }