gitlab.com/yawning/chacha20.git@v0.0.0-20230427033715-7877545b1b37/internal/hardware/impl_amd64.go (about)

     1  // Copryright (C) 2019 Yawning Angel
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  // +build amd64,!noasm
    17  
    18  package hardware
    19  
    20  import (
    21  	"golang.org/x/sys/cpu"
    22  
    23  	"gitlab.com/yawning/chacha20.git/internal/api"
    24  )
    25  
    26  //go:noescape
    27  func blocksAVX2(s *[api.StateSize]uint32, in, out []byte)
    28  
    29  //go:noescape
    30  func hChaChaAVX2(key, nonce []byte, dst *byte)
    31  
    32  //go:noescape
    33  func blocksSSSE3(s *[api.StateSize]uint32, in, out []byte)
    34  
    35  //go:noescape
    36  func hChaChaSSSE3(key, nonce []byte, dst *byte)
    37  
    38  type implAmd64 struct {
    39  	name string
    40  
    41  	blocksFn  func(*[api.StateSize]uint32, []byte, []byte, int)
    42  	hChaChaFn func([]byte, []byte, *byte)
    43  }
    44  
    45  func (impl *implAmd64) Name() string {
    46  	return impl.name
    47  }
    48  
    49  func (impl *implAmd64) Blocks(x *[api.StateSize]uint32, dst, src []byte, nrBlocks int) {
    50  	impl.blocksFn(x, dst, src, nrBlocks)
    51  }
    52  
    53  func (impl *implAmd64) HChaCha(key, nonce []byte, dst []byte) {
    54  	impl.hChaChaFn(key, nonce, &dst[0])
    55  }
    56  
    57  func blockWrapper(fn func(*[api.StateSize]uint32, []byte, []byte)) func(*[api.StateSize]uint32, []byte, []byte, int) {
    58  	return func(x *[api.StateSize]uint32, dst, src []byte, nrBlocks int) {
    59  		sz := nrBlocks * api.BlockSize
    60  		if src != nil {
    61  			fn(x, src[:sz], dst[:sz])
    62  		} else {
    63  			// Sub-optimal, but the compiler special cases this to an assembly
    64  			// optimized runtime.memclrNoHeapPointers, so it's not terrible.
    65  			for i := range dst[:sz] {
    66  				dst[i] = 0
    67  			}
    68  			fn(x, dst[:sz], dst[:sz])
    69  		}
    70  	}
    71  }
    72  
    73  func init() {
    74  	if cpu.X86.HasAVX2 {
    75  		hardwareImpls = append(hardwareImpls, &implAmd64{
    76  			name:      "amd64_avx2",
    77  			blocksFn:  blockWrapper(blocksAVX2),
    78  			hChaChaFn: hChaChaAVX2,
    79  		})
    80  	}
    81  	if cpu.X86.HasSSSE3 {
    82  		hardwareImpls = append(hardwareImpls, &implAmd64{
    83  			name:      "amd64_ssse3",
    84  			blocksFn:  blockWrapper(blocksSSSE3),
    85  			hChaChaFn: hChaChaSSSE3,
    86  		})
    87  	}
    88  }