chacha20poly1305_amd64.mx raw

   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  
   7  package chacha20poly1305
   8  
   9  import (
  10  	"encoding/binary"
  11  
  12  	"golang.org/x/crypto/internal/alias"
  13  	"golang.org/x/sys/cpu"
  14  )
  15  
  16  //go:noescape
  17  func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
  18  
  19  //go:noescape
  20  func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
  21  
  22  var (
  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.
  28  func 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  
  49  func (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  
  65  func (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  }
  87