github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/sm4/cipher_asm.go (about) 1 //go:build amd64 || arm64 2 // +build amd64 arm64 3 4 package sm4 5 6 import ( 7 "crypto/cipher" 8 9 "github.com/hxx258456/ccgo/internal/subtle" 10 "golang.org/x/sys/cpu" 11 ) 12 13 var supportSM4 = cpu.ARM64.HasSM4 14 var supportsAES = cpu.X86.HasAES || cpu.ARM64.HasAES 15 var supportsGFMUL = cpu.X86.HasPCLMULQDQ || cpu.ARM64.HasPMULL 16 var useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2 17 18 //goland:noinspection GoSnakeCaseUsage 19 const ( 20 INST_AES int = iota 21 INST_SM4 22 ) 23 24 //go:noescape 25 //goland:noinspection GoUnusedParameter 26 func encryptBlocksAsm(xk *uint32, dst, src []byte, inst int) 27 28 //go:noescape 29 //goland:noinspection GoUnusedParameter 30 func encryptBlockAsm(xk *uint32, dst, src *byte, inst int) 31 32 //go:noescape 33 //goland:noinspection GoUnusedParameter 34 func expandKeyAsm(key *byte, ck, enc, dec *uint32, inst int) 35 36 type sm4CipherAsm struct { 37 sm4Cipher 38 batchBlocks int 39 blocksSize int 40 } 41 42 type sm4CipherNI struct { 43 sm4Cipher 44 } 45 46 func newCipherNI(key []byte) (cipher.Block, error) { 47 c := &sm4CipherNI{sm4Cipher{make([]uint32, rounds), make([]uint32, rounds)}} 48 expandKeyAsm(&key[0], &ck[0], &c.enc[0], &c.dec[0], INST_SM4) 49 if supportsGFMUL { 50 return &sm4CipherNIGCM{c}, nil 51 } 52 return c, nil 53 } 54 55 func (c *sm4CipherNI) Encrypt(dst, src []byte) { 56 if len(src) < BlockSize { 57 panic("sm4: input not full block") 58 } 59 if len(dst) < BlockSize { 60 panic("sm4: output not full block") 61 } 62 if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { 63 panic("sm4: invalid buffer overlap") 64 } 65 encryptBlockAsm(&c.enc[0], &dst[0], &src[0], INST_SM4) 66 } 67 68 func (c *sm4CipherNI) Decrypt(dst, src []byte) { 69 if len(src) < BlockSize { 70 panic("sm4: input not full block") 71 } 72 if len(dst) < BlockSize { 73 panic("sm4: output not full block") 74 } 75 if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { 76 panic("sm4: invalid buffer overlap") 77 } 78 encryptBlockAsm(&c.dec[0], &dst[0], &src[0], INST_SM4) 79 } 80 81 func newCipher(key []byte) (cipher.Block, error) { 82 if supportSM4 { 83 return newCipherNI(key) 84 } 85 86 if !supportsAES { 87 return newCipherGeneric(key) 88 } 89 90 blocks := 4 91 if useAVX2 { 92 blocks = 8 93 } 94 c := &sm4CipherAsm{sm4Cipher{make([]uint32, rounds), make([]uint32, rounds)}, blocks, blocks * BlockSize} 95 expandKeyAsm(&key[0], &ck[0], &c.enc[0], &c.dec[0], INST_AES) 96 if supportsGFMUL { 97 return &sm4CipherGCM{c}, nil 98 } 99 return c, nil 100 } 101 102 func (sm4c *sm4CipherAsm) BlockSize() int { return BlockSize } 103 104 func (sm4c *sm4CipherAsm) Concurrency() int { return sm4c.batchBlocks } 105 106 func (sm4c *sm4CipherAsm) Encrypt(dst, src []byte) { 107 if len(src) < BlockSize { 108 panic("sm4: input not full block") 109 } 110 if len(dst) < BlockSize { 111 panic("sm4: output not full block") 112 } 113 if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { 114 panic("sm4: invalid buffer overlap") 115 } 116 encryptBlockAsm(&sm4c.enc[0], &dst[0], &src[0], INST_AES) 117 } 118 119 func (sm4c *sm4CipherAsm) EncryptBlocks(dst, src []byte) { 120 if len(src) < sm4c.blocksSize { 121 panic("sm4: input not full blocks") 122 } 123 if len(dst) < sm4c.blocksSize { 124 panic("sm4: output not full blocks") 125 } 126 if subtle.InexactOverlap(dst[:sm4c.blocksSize], src[:sm4c.blocksSize]) { 127 panic("sm4: invalid buffer overlap") 128 } 129 encryptBlocksAsm(&sm4c.enc[0], dst, src, INST_AES) 130 } 131 132 func (sm4c *sm4CipherAsm) Decrypt(dst, src []byte) { 133 if len(src) < BlockSize { 134 panic("sm4: input not full block") 135 } 136 if len(dst) < BlockSize { 137 panic("sm4: output not full block") 138 } 139 if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { 140 panic("sm4: invalid buffer overlap") 141 } 142 encryptBlockAsm(&sm4c.dec[0], &dst[0], &src[0], INST_AES) 143 } 144 145 func (sm4c *sm4CipherAsm) DecryptBlocks(dst, src []byte) { 146 if len(src) < sm4c.blocksSize { 147 panic("sm4: input not full blocks") 148 } 149 if len(dst) < sm4c.blocksSize { 150 panic("sm4: output not full blocks") 151 } 152 if subtle.InexactOverlap(dst[:sm4c.blocksSize], src[:sm4c.blocksSize]) { 153 panic("sm4: invalid buffer overlap") 154 } 155 encryptBlocksAsm(&sm4c.dec[0], dst, src, INST_AES) 156 } 157 158 // expandKey is used by BenchmarkExpand to ensure that the asm implementation 159 // of key expansion is used for the benchmark when it is available. 160 func expandKey(key []byte, enc, dec []uint32) { 161 if supportSM4 { 162 expandKeyAsm(&key[0], &ck[0], &enc[0], &dec[0], INST_SM4) 163 } else if supportsAES { 164 expandKeyAsm(&key[0], &ck[0], &enc[0], &dec[0], INST_AES) 165 } else { 166 expandKeyGo(key, enc, dec) 167 } 168 }