github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/crypto/aes/cipher_asm.go (about) 1 // Copyright 2012 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 (amd64 || arm64 || ppc64 || ppc64le) && !purego 6 7 package aes 8 9 import ( 10 "crypto/cipher" 11 "crypto/internal/alias" 12 "crypto/internal/boring" 13 "internal/cpu" 14 "internal/goarch" 15 ) 16 17 // defined in asm_*.s 18 19 //go:noescape 20 func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) 21 22 //go:noescape 23 func decryptBlockAsm(nr int, xk *uint32, dst, src *byte) 24 25 //go:noescape 26 func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32) 27 28 type aesCipherAsm struct { 29 aesCipher 30 } 31 32 // aesCipherGCM implements crypto/cipher.gcmAble so that crypto/cipher.NewGCM 33 // will use the optimised implementation in aes_gcm.go when possible. 34 // Instances of this type only exist when hasGCMAsm returns true. Likewise, 35 // the gcmAble implementation is in aes_gcm.go. 36 type aesCipherGCM struct { 37 aesCipherAsm 38 } 39 40 var supportsAES = cpu.X86.HasAES || cpu.ARM64.HasAES || goarch.IsPpc64 == 1 || goarch.IsPpc64le == 1 41 var supportsGFMUL = cpu.X86.HasPCLMULQDQ || cpu.ARM64.HasPMULL 42 43 func newCipher(key []byte) (cipher.Block, error) { 44 if !supportsAES { 45 return newCipherGeneric(key) 46 } 47 n := len(key) + 28 48 c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}} 49 var rounds int 50 switch len(key) { 51 case 128 / 8: 52 rounds = 10 53 case 192 / 8: 54 rounds = 12 55 case 256 / 8: 56 rounds = 14 57 default: 58 return nil, KeySizeError(len(key)) 59 } 60 61 expandKeyAsm(rounds, &key[0], &c.enc[0], &c.dec[0]) 62 if supportsAES && supportsGFMUL { 63 return &aesCipherGCM{c}, nil 64 } 65 return &c, nil 66 } 67 68 func (c *aesCipherAsm) BlockSize() int { return BlockSize } 69 70 func (c *aesCipherAsm) Encrypt(dst, src []byte) { 71 boring.Unreachable() 72 if len(src) < BlockSize { 73 panic("crypto/aes: input not full block") 74 } 75 if len(dst) < BlockSize { 76 panic("crypto/aes: output not full block") 77 } 78 if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { 79 panic("crypto/aes: invalid buffer overlap") 80 } 81 encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0]) 82 } 83 84 func (c *aesCipherAsm) Decrypt(dst, src []byte) { 85 boring.Unreachable() 86 if len(src) < BlockSize { 87 panic("crypto/aes: input not full block") 88 } 89 if len(dst) < BlockSize { 90 panic("crypto/aes: output not full block") 91 } 92 if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { 93 panic("crypto/aes: invalid buffer overlap") 94 } 95 decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0]) 96 } 97 98 // expandKey is used by BenchmarkExpand to ensure that the asm implementation 99 // of key expansion is used for the benchmark when it is available. 100 func expandKey(key []byte, enc, dec []uint32) { 101 if supportsAES { 102 rounds := 10 // rounds needed for AES128 103 switch len(key) { 104 case 192 / 8: 105 rounds = 12 106 case 256 / 8: 107 rounds = 14 108 } 109 expandKeyAsm(rounds, &key[0], &enc[0], &dec[0]) 110 } else { 111 expandKeyGo(key, enc, dec) 112 } 113 }