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//go:build gc && !purego
 6
 7package chacha20poly1305
 8
 9import (
10	"encoding/binary"
11
12	"golang.org/x/crypto/internal/alias"
13	"golang.org/x/sys/cpu"
14)
15
16//go:noescape
17func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
18
19//go:noescape
20func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
21
22var (
23	useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
24)
25
26// setupState writes a ChaCha20 input matrix to state. See
27// https://tools.ietf.org/html/rfc7539#section-2.3.
28func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
29	state[0] = 0x61707865
30	state[1] = 0x3320646e
31	state[2] = 0x79622d32
32	state[3] = 0x6b206574
33
34	state[4] = binary.LittleEndian.Uint32(key[0:4])
35	state[5] = binary.LittleEndian.Uint32(key[4:8])
36	state[6] = binary.LittleEndian.Uint32(key[8:12])
37	state[7] = binary.LittleEndian.Uint32(key[12:16])
38	state[8] = binary.LittleEndian.Uint32(key[16:20])
39	state[9] = binary.LittleEndian.Uint32(key[20:24])
40	state[10] = binary.LittleEndian.Uint32(key[24:28])
41	state[11] = binary.LittleEndian.Uint32(key[28:32])
42
43	state[12] = 0
44	state[13] = binary.LittleEndian.Uint32(nonce[0:4])
45	state[14] = binary.LittleEndian.Uint32(nonce[4:8])
46	state[15] = binary.LittleEndian.Uint32(nonce[8:12])
47}
48
49func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
50	if !cpu.X86.HasSSSE3 {
51		return c.sealGeneric(dst, nonce, plaintext, additionalData)
52	}
53
54	var state [16]uint32
55	setupState(&state, &c.key, nonce)
56
57	ret, out := sliceForAppend(dst, len(plaintext)+16)
58	if alias.InexactOverlap(out, plaintext) {
59		panic("chacha20poly1305: invalid buffer overlap")
60	}
61	chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
62	return ret
63}
64
65func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
66	if !cpu.X86.HasSSSE3 {
67		return c.openGeneric(dst, nonce, ciphertext, additionalData)
68	}
69
70	var state [16]uint32
71	setupState(&state, &c.key, nonce)
72
73	ciphertext = ciphertext[:len(ciphertext)-16]
74	ret, out := sliceForAppend(dst, len(ciphertext))
75	if alias.InexactOverlap(out, ciphertext) {
76		panic("chacha20poly1305: invalid buffer overlap")
77	}
78	if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
79		for i := range out {
80			out[i] = 0
81		}
82		return nil, errOpen
83	}
84
85	return ret, nil
86}