mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-22 10:16:18 +08:00
Compare commits
68 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7b75b6b26b | ||
![]() |
5aacbc2011 | ||
![]() |
fe532e12b4 | ||
![]() |
1dc82305e4 | ||
![]() |
ed256a9ea3 | ||
![]() |
d8c6788e8f | ||
![]() |
0ef30b3ab5 | ||
![]() |
d3eece5560 | ||
![]() |
0af92d8e48 | ||
![]() |
bf644fbb4e | ||
![]() |
359b46453b | ||
![]() |
b8d52dd11d | ||
![]() |
9ea8293d10 | ||
![]() |
e8a847e005 | ||
![]() |
a7c4473a48 | ||
![]() |
11d0438cc4 | ||
![]() |
88df15c64c | ||
![]() |
3eea15b3b8 | ||
![]() |
dd69d32930 | ||
![]() |
a84fec09af | ||
![]() |
c43e0488a6 | ||
![]() |
a4affe6006 | ||
![]() |
3cc92436ee | ||
![]() |
93c965f3c1 | ||
![]() |
d8eb166dfc | ||
![]() |
2d3329a2ea | ||
![]() |
f41a5c69e7 | ||
![]() |
cf027254dc | ||
![]() |
069babe703 | ||
![]() |
5734e67634 | ||
![]() |
82ccb95527 | ||
![]() |
e79aab4935 | ||
![]() |
c32a9849f8 | ||
![]() |
7ec46d700d | ||
![]() |
7a5253bfb5 | ||
![]() |
d6f18a2cbf | ||
![]() |
bdb169b06b | ||
![]() |
43ffd49e2f | ||
![]() |
e9692d23ab | ||
![]() |
21f96e536b | ||
![]() |
a49eecd572 | ||
![]() |
537c80a28b | ||
![]() |
5edcb0f966 | ||
![]() |
65a69ad83c | ||
![]() |
71b196a5ac | ||
![]() |
500cb8a418 | ||
![]() |
762cbbf0c6 | ||
![]() |
9d6f8087f9 | ||
![]() |
a6d8014ac9 | ||
![]() |
d7a6169fbf | ||
![]() |
67f187b1d3 | ||
![]() |
759bb4c0b9 | ||
![]() |
5ade794e6b | ||
![]() |
89962cf1e3 | ||
![]() |
d433e416fa | ||
![]() |
2c0f5f68fc | ||
![]() |
3d4dd002a4 | ||
![]() |
9ba88a32a4 | ||
![]() |
0bb54adc1e | ||
![]() |
a98b806453 | ||
![]() |
51a003b022 | ||
![]() |
dc1c5806c9 | ||
![]() |
869be23867 | ||
![]() |
8a25134c82 | ||
![]() |
27e7ceacbc | ||
![]() |
ec8580b01f | ||
![]() |
2192b702b0 | ||
![]() |
d03a8fba3f |
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
goVer: ['1.18', '1.19', '1.21', '1.22', '1.23']
|
goVer: ['1.23', '1.24']
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repo
|
- name: Checkout Repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@ -23,19 +23,19 @@ jobs:
|
|||||||
go-version: ${{ matrix.goVer }}
|
go-version: ${{ matrix.goVer }}
|
||||||
|
|
||||||
- name: Test with Coverage
|
- name: Test with Coverage
|
||||||
if: ${{ matrix.goVer == '1.18' }}
|
if: ${{ matrix.goVer == '1.23' }}
|
||||||
run: go test -coverpkg=./... -v -short -race -coverprofile=coverage1.txt -covermode=atomic ./...
|
run: go test -coverpkg=./... -v -short -race -coverprofile=coverage1.txt -covermode=atomic ./...
|
||||||
env:
|
env:
|
||||||
GODEBUG: x509sha1=1
|
GODEBUG: x509sha1=1
|
||||||
|
|
||||||
- name: Test Generic with Coverage
|
- name: Test Generic with Coverage
|
||||||
if: ${{ matrix.goVer == '1.18' }}
|
if: ${{ matrix.goVer == '1.23' }}
|
||||||
run: go test -coverpkg=./... -v -short -tags purego -coverprofile=coverage2.txt -covermode=atomic ./...
|
run: go test -coverpkg=./... -v -short -tags purego -coverprofile=coverage2.txt -covermode=atomic ./...
|
||||||
env:
|
env:
|
||||||
GODEBUG: x509sha1=1
|
GODEBUG: x509sha1=1
|
||||||
|
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
if: ${{ matrix.goVer == '1.18' }}
|
if: ${{ matrix.goVer == '1.23' }}
|
||||||
uses: codecov/codecov-action@v5
|
uses: codecov/codecov-action@v5
|
||||||
with:
|
with:
|
||||||
files: ./coverage1.txt,./coverage2.txt
|
files: ./coverage1.txt,./coverage2.txt
|
||||||
@ -48,19 +48,19 @@ jobs:
|
|||||||
FORCE_SM4BLOCK_AESNI: 1
|
FORCE_SM4BLOCK_AESNI: 1
|
||||||
|
|
||||||
- name: Test only
|
- name: Test only
|
||||||
if: ${{ matrix.goVer != '1.18' }}
|
if: ${{ matrix.goVer != '1.23' }}
|
||||||
run: go test -short ./...
|
run: go test -short ./...
|
||||||
env:
|
env:
|
||||||
GODEBUG: x509sha1=1
|
GODEBUG: x509sha1=1
|
||||||
|
|
||||||
- name: Test Generic only
|
- name: Test Generic only
|
||||||
if: ${{ matrix.goVer != '1.18' && matrix.goVer != '1.23' }}
|
if: ${{ matrix.goVer != '1.23' }}
|
||||||
run: go test -short -tags purego ./...
|
run: go test -short -tags purego ./...
|
||||||
env:
|
env:
|
||||||
GODEBUG: x509sha1=1
|
GODEBUG: x509sha1=1
|
||||||
|
|
||||||
- name: Test Plugin only
|
- name: Test Plugin only
|
||||||
if: ${{ matrix.goVer != '1.18' }}
|
if: ${{ matrix.goVer == '1.23' }}
|
||||||
run: go test -short -tags plugin ./...
|
run: go test -short -tags plugin ./...
|
||||||
env:
|
env:
|
||||||
GODEBUG: x509sha1=1
|
GODEBUG: x509sha1=1
|
||||||
|
2
.github/workflows/macos.yml
vendored
2
.github/workflows/macos.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.22
|
go-version: 1.23
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: go build -v ./...
|
run: go build -v ./...
|
||||||
|
26
.github/workflows/test_ppc64.yaml
vendored
26
.github/workflows/test_ppc64.yaml
vendored
@ -14,7 +14,7 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.19.x]
|
go-version: [1.23.x]
|
||||||
arch: [ppc64le]
|
arch: [ppc64le]
|
||||||
ppc64: [power8]
|
ppc64: [power8]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -36,30 +36,6 @@ jobs:
|
|||||||
GOARCH: ${{ matrix.arch }}
|
GOARCH: ${{ matrix.arch }}
|
||||||
GOPPC64: ${{ matrix.ppc64 }}
|
GOPPC64: ${{ matrix.ppc64 }}
|
||||||
|
|
||||||
- name: Test bn256
|
|
||||||
run: go test -v ./sm9/bn256/...
|
|
||||||
env:
|
|
||||||
GOARCH: ${{ matrix.arch }}
|
|
||||||
GOPPC64: ${{ matrix.ppc64 }}
|
|
||||||
|
|
||||||
- name: Test ZUC
|
|
||||||
run: go test -v ./zuc/...
|
|
||||||
env:
|
|
||||||
GOARCH: ${{ matrix.arch }}
|
|
||||||
GOPPC64: ${{ matrix.ppc64 }}
|
|
||||||
|
|
||||||
- name: Test SM3
|
|
||||||
run: go test -v ./sm3/...
|
|
||||||
env:
|
|
||||||
GOARCH: ${{ matrix.arch }}
|
|
||||||
GOPPC64: ${{ matrix.ppc64 }}
|
|
||||||
|
|
||||||
- name: Test SM4
|
|
||||||
run: go test -v -short ./sm4/...
|
|
||||||
env:
|
|
||||||
GOARCH: ${{ matrix.arch }}
|
|
||||||
GOPPC64: ${{ matrix.ppc64 }}
|
|
||||||
|
|
||||||
- name: Test Cipher
|
- name: Test Cipher
|
||||||
run: go test -v -short ./cipher/...
|
run: go test -v -short ./cipher/...
|
||||||
env:
|
env:
|
||||||
|
2
.github/workflows/test_qemu.yml
vendored
2
.github/workflows/test_qemu.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.18.x]
|
go-version: [1.23.x]
|
||||||
arch: [arm64]
|
arch: [arm64]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
2
.github/workflows/test_riscv64.yaml
vendored
2
.github/workflows/test_riscv64.yaml
vendored
@ -14,7 +14,7 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.22.x]
|
go-version: [1.23.x]
|
||||||
arch: [riscv64]
|
arch: [riscv64]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
7
.github/workflows/test_s390x.yaml
vendored
7
.github/workflows/test_s390x.yaml
vendored
@ -14,7 +14,7 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.19.x]
|
go-version: [1.23.x]
|
||||||
arch: [s390x]
|
arch: [s390x]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@ -34,11 +34,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GOARCH: ${{ matrix.arch }}
|
GOARCH: ${{ matrix.arch }}
|
||||||
|
|
||||||
- name: Test sm3
|
|
||||||
run: go test -v ./sm3/...
|
|
||||||
env:
|
|
||||||
GOARCH: ${{ matrix.arch }}
|
|
||||||
|
|
||||||
- name: Test Cipher
|
- name: Test Cipher
|
||||||
run: go test -v -short ./cipher/...
|
run: go test -v -short ./cipher/...
|
||||||
env:
|
env:
|
||||||
|
2
.github/workflows/test_sm_ni.yml
vendored
2
.github/workflows/test_sm_ni.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.18.x]
|
go-version: [1.23.x]
|
||||||
arch: [arm64]
|
arch: [arm64]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -1,23 +1,27 @@
|
|||||||
# 免责申明
|
# 免责声明
|
||||||
|
|
||||||
## 声明
|
## 版权声明
|
||||||
|
本项目(gmsm)代码的版权归[Sun Yimin](mailto:emman.sun@foxmail.com)所有,并按照[MIT](https://github.com/emmansun/gmsm/blob/main/LICENSE)进行分发。使用本项目的代码时,必须遵守相应的许可证条款。
|
||||||
|
|
||||||
任何直接或间接因使用本项目(gmsm)的任何内容所导致的全部后果与本项目(gmsm)的开发者无关,若使用者无法对使用本项目(gmsm)后的任何后果负责,请不要使用本项目(gmsm)的任何内容。若该项目(gmsm)的任何内容侵犯了您的法律权益,请联系 emman.sun@foxmail.com,作者会第一时间删除侵权内容。
|
## 免责条款
|
||||||
|
|
||||||
## 认证
|
1. **无担保声明**
|
||||||
|
本项目以“原样”提供,不提供任何形式的明示或暗示担保,包括但不限于对适销性、特定用途适用性和非侵权性的担保。
|
||||||
|
|
||||||
本项目(gmsm)**没有**经过相关机构资质认证。
|
2. **责任限制**
|
||||||
|
对于因使用或无法使用本项目代码而导致的任何直接、间接、偶然、特殊、典型或惩罚性损害(包括但不限于数据丢失、利润损失、业务中断等),项目作者或贡献者概不负责。
|
||||||
|
|
||||||
## 保证
|
3. **使用风险**
|
||||||
|
使用本项目代码的风险由使用者自行承担。使用者在使用本项目时,应自行评估代码的适用性和安全性,并根据实际需求进行测试和调整。
|
||||||
|
|
||||||
本项目(gmsm)不提供任何形式的保证。所有与使用本项目(gmsm)软件库及源代码相关的直接或间接风险均由用户自行承担。本项目(gmsm)提供的所有代码,并不对性能、适用性、适销性及其他方面提供任何保证。
|
4. **第三方依赖**
|
||||||
|
本项目可能依赖于第三方库或服务,这些库或服务的使用应遵守其各自的许可证条款。项目作者或贡献者不对第三方库或服务的稳定性、安全性或合法性负责。
|
||||||
|
|
||||||
本项目(gmsm)实现的内容可能包含不准确性或错误,我们不对内容的准确性进行保证。如果您发现本项目(gmsm)内容包含错误,请直接提交错误至[issue tracker](https://github.com/emmansun/gmsm/issues),或者提交代码至[pull requests](https://github.com/emmansun/gmsm/pulls)。
|
5. **法律合规**
|
||||||
|
使用本项目代码时,使用者应确保遵守所在国家或地区的法律法规。如因使用本项目代码而违反相关法律,使用者需自行承担法律责任。
|
||||||
|
|
||||||
## 您的行为
|
6. **产品认证**
|
||||||
|
本项目(gmsm)**没有**经过相关机构(包括但不限于**国家密码管理局商用密码检测中心**)认证,也不承诺会进行相关认证工作。
|
||||||
|
|
||||||
当您以任何方式使用本项目(gmsm)软件库及源代码时,说明您已经同意并接受本页面的所有信息。
|
7. **修改与分发**
|
||||||
|
如果您修改本项目代码并重新分发,请确保保留上述版权声明和免责条款,并明确标注您的修改内容。
|
||||||
## 联系方式
|
|
||||||
|
|
||||||
联系邮箱:emman.sun@foxmail.com(相关事务请发函至该邮箱)
|
|
||||||
|
@ -43,7 +43,7 @@ Go语言商用密码软件,简称**GMSM**,一个安全、高性能、易于
|
|||||||
|
|
||||||
- **SMX509** - Go语言X509包的分支,加入了商用密码支持。
|
- **SMX509** - Go语言X509包的分支,加入了商用密码支持。
|
||||||
|
|
||||||
- **PADDING** - 一些填充方法实现(非常量时间运行):**pkcs7**,这是当前主要使用的填充方式,对应**GB/T 17964-2021**的附录C.2 填充方法 1;**iso9797m2**,对应**GB/T 17964-2021**的附录C.3 填充方法 2;**ansix923**,对应ANSI X9.23标准。**GB/T 17964-2021**的附录C.4 填充方法 3,目前没有实现,它对应ISO/IEC_9797-1 padding method 3,如有使用需求,可以考虑实现。
|
- **PADDING** - 一些填充方法实现(非常量时间运行):**pkcs7**,这是当前主要使用的填充方式,对应**GB/T 17964-2021**的附录C.2 填充方法 1;**iso9797m2**,对应**GB/T 17964-2021**的附录C.3 填充方法 2;**ansix923**,对应ANSI X9.23标准。**GB/T 17964-2021**的附录C.4 填充方法 3,对应ISO/IEC_9797-1 padding method 3。
|
||||||
|
|
||||||
- **PKCS7** - [mozilla-services/pkcs7](https://github.com/mozilla-services/pkcs7) 项目(该项目已于2024年2月10日被归档)的分支,加入了商用密码支持。
|
- **PKCS7** - [mozilla-services/pkcs7](https://github.com/mozilla-services/pkcs7) 项目(该项目已于2024年2月10日被归档)的分支,加入了商用密码支持。
|
||||||
|
|
||||||
|
@ -7,16 +7,16 @@ package cbcmac
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
"crypto/subtle"
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/internal/subtle"
|
|
||||||
"github.com/emmansun/gmsm/padding"
|
"github.com/emmansun/gmsm/padding"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reference: GB/T 15821.1-2020 Security techniques
|
// Reference: GB/T 15821.1-2020 Security techniques
|
||||||
// Message authentication codes - Part 1: Mechanisms using block ciphers
|
// Message authentication codes - Part 1: Mechanisms using block ciphers
|
||||||
|
|
||||||
// BockCipherMAC is the interface that wraps the basic MAC method.
|
// BlockCipherMAC is the interface that wraps the basic MAC method.
|
||||||
type BockCipherMAC interface {
|
type BlockCipherMAC interface {
|
||||||
// Size returns the MAC value's number of bytes.
|
// Size returns the MAC value's number of bytes.
|
||||||
Size() int
|
Size() int
|
||||||
|
|
||||||
@ -33,14 +33,21 @@ type cbcmac struct {
|
|||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCBCMAC returns a CBC-MAC instance that implements the MAC with the given block cipher.
|
// NewCBCMAC returns a CBC-MAC (GB/T 15821.1-2020 MAC scheme 1) instance that
|
||||||
// The padding scheme is ISO/IEC 9797-1 method 2.
|
// implements the MAC with the given block cipher. The padding scheme is ISO/IEC 9797-1 method 2.
|
||||||
// GB/T 15821.1-2020 MAC scheme 1
|
func NewCBCMAC(b cipher.Block, size int) BlockCipherMAC {
|
||||||
func NewCBCMAC(b cipher.Block, size int) BockCipherMAC {
|
return NewCBCMACWithPadding(b, size, padding.NewISO9797M2Padding)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCBCMACWithPadding creates a new CBC-MAC (Cipher Block Chaining Message Authentication Code)
|
||||||
|
// with the specified block cipher, MAC size, and padding function. The MAC size must be greater
|
||||||
|
// than 0 and less than or equal to the block size of the cipher. If the size is invalid, the
|
||||||
|
// function will panic. The padding function is used to pad the input to the block size of the cipher.
|
||||||
|
func NewCBCMACWithPadding(b cipher.Block, size int, newPaddingFunc padding.NewPaddingFunc) BlockCipherMAC {
|
||||||
if size <= 0 || size > b.BlockSize() {
|
if size <= 0 || size > b.BlockSize() {
|
||||||
panic("cbcmac: invalid size")
|
panic("cbcmac: invalid size")
|
||||||
}
|
}
|
||||||
return &cbcmac{b: b, pad: padding.NewISO9797M2Padding(uint(b.BlockSize())), size: size}
|
return &cbcmac{b: b, pad: newPaddingFunc(uint(b.BlockSize())), size: size}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cbcmac) Size() int {
|
func (c *cbcmac) Size() int {
|
||||||
@ -68,10 +75,14 @@ type emac struct {
|
|||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEMAC returns an EMAC instance that implements MAC with the given block cipher.
|
// NewEMAC returns an EMAC (GB/T 15821.1-2020 MAC scheme 2) instance that
|
||||||
// The padding scheme is ISO/IEC 9797-1 method 2.
|
// implements MAC with the given block cipher. The padding scheme is ISO/IEC 9797-1 method 2.
|
||||||
// GB/T 15821.1-2020 MAC scheme 2
|
func NewEMAC(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int) BlockCipherMAC {
|
||||||
func NewEMAC(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int) BockCipherMAC {
|
return NewEMACWithPadding(creator, key1, key2, size, padding.NewISO9797M2Padding)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEMACWithPadding creates a new instance of EMAC (Encrypted Message Authentication Code) with padding.
|
||||||
|
func NewEMACWithPadding(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int, newPaddingFunc padding.NewPaddingFunc) BlockCipherMAC {
|
||||||
var b1, b2 cipher.Block
|
var b1, b2 cipher.Block
|
||||||
var err error
|
var err error
|
||||||
if b1, err = creator(key1); err != nil {
|
if b1, err = creator(key1); err != nil {
|
||||||
@ -83,7 +94,7 @@ func NewEMAC(creator func(key []byte) (cipher.Block, error), key1, key2 []byte,
|
|||||||
if b2, err = creator(key2); err != nil {
|
if b2, err = creator(key2); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return &emac{pad: padding.NewISO9797M2Padding(uint(b1.BlockSize())), b1: b1, b2: b2, size: size}
|
return &emac{pad: newPaddingFunc(uint(b1.BlockSize())), b1: b1, b2: b2, size: size}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *emac) Size() int {
|
func (e *emac) Size() int {
|
||||||
@ -105,11 +116,15 @@ func (e *emac) MAC(src []byte) []byte {
|
|||||||
|
|
||||||
type ansiRetailMAC emac
|
type ansiRetailMAC emac
|
||||||
|
|
||||||
// NewANSIRetailMAC returns an ANSI Retail MAC instance that implements MAC with the given block cipher.
|
// NewANSIRetailMAC returns an ANSI Retail MAC (GB/T 15821.1-2020 MAC scheme 3) instance that
|
||||||
// The padding scheme is ISO/IEC 9797-1 method 2.
|
// implements MAC with the given block cipher. The padding scheme is ISO/IEC 9797-1 method 2.
|
||||||
// GB/T 15821.1-2020 MAC scheme 3
|
func NewANSIRetailMAC(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int) BlockCipherMAC {
|
||||||
func NewANSIRetailMAC(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int) BockCipherMAC {
|
return NewANSIRetailMACWithPadding(creator, key1, key2, size, padding.NewISO9797M2Padding)
|
||||||
return (*ansiRetailMAC)(NewEMAC(creator, key1, key2, size).(*emac))
|
}
|
||||||
|
|
||||||
|
// NewANSIRetailMACWithPadding creates a new ANSI Retail MAC with padding.
|
||||||
|
func NewANSIRetailMACWithPadding(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int, newPaddingFunc padding.NewPaddingFunc) BlockCipherMAC {
|
||||||
|
return (*ansiRetailMAC)(NewEMACWithPadding(creator, key1, key2, size, newPaddingFunc).(*emac))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ansiRetailMAC) Size() int {
|
func (e *ansiRetailMAC) Size() int {
|
||||||
@ -136,10 +151,14 @@ type macDES struct {
|
|||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMACDES returns a MAC-DES instance that implements MAC with the given block cipher.
|
// NewMACDES returns a MAC-DES (GB/T 15821.1-2020 MAC scheme 4) instance that
|
||||||
// The padding scheme is ISO/IEC 9797-1 method 2.
|
// implements MAC with the given block cipher. The padding scheme is ISO/IEC 9797-1 method 2.
|
||||||
// GB/T 15821.1-2020 MAC scheme 4
|
func NewMACDES(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int) BlockCipherMAC {
|
||||||
func NewMACDES(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int) BockCipherMAC {
|
return NewMACDESWithPadding(creator, key1, key2, size, padding.NewISO9797M2Padding)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMACDESWithPadding creates a new BlockCipherMAC using DES encryption with padding.
|
||||||
|
func NewMACDESWithPadding(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int, newPaddingFunc padding.NewPaddingFunc) BlockCipherMAC {
|
||||||
var b1, b2, b3 cipher.Block
|
var b1, b2, b3 cipher.Block
|
||||||
var err error
|
var err error
|
||||||
if b1, err = creator(key1); err != nil {
|
if b1, err = creator(key1); err != nil {
|
||||||
@ -153,13 +172,13 @@ func NewMACDES(creator func(key []byte) (cipher.Block, error), key1, key2 []byte
|
|||||||
}
|
}
|
||||||
key3 := make([]byte, len(key2))
|
key3 := make([]byte, len(key2))
|
||||||
copy(key3, key2)
|
copy(key3, key2)
|
||||||
for i := 0; i < len(key3); i++ {
|
for i := range key3 {
|
||||||
key3[i] ^= 0xF0
|
key3[i] ^= 0xF0
|
||||||
}
|
}
|
||||||
if b3, err = creator(key3); err != nil {
|
if b3, err = creator(key3); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return &macDES{pad: padding.NewISO9797M2Padding(uint(b1.BlockSize())), b1: b1, b2: b2, b3: b3, size: size}
|
return &macDES{pad: newPaddingFunc(uint(b1.BlockSize())), b1: b1, b2: b2, b3: b3, size: size}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *macDES) Size() int {
|
func (m *macDES) Size() int {
|
||||||
@ -194,8 +213,7 @@ type cmac struct {
|
|||||||
len uint64
|
len uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCMAC returns a CMAC instance that implements MAC with the given block cipher.
|
// NewCMAC returns a CMAC (GB/T 15821.1-2020 MAC scheme 5) instance that implements MAC with the given block cipher.
|
||||||
// GB/T 15821.1-2020 MAC scheme 5
|
|
||||||
//
|
//
|
||||||
// Reference: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38B.pdf
|
// Reference: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38B.pdf
|
||||||
func NewCMAC(b cipher.Block, size int) *cmac {
|
func NewCMAC(b cipher.Block, size int) *cmac {
|
||||||
@ -334,9 +352,14 @@ type lmac struct {
|
|||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLMAC returns an LMAC instance that implements MAC with the given block cipher.
|
// NewLMAC returns an LMAC (GB/T 15821.1-2020 MAC scheme 6) instance that
|
||||||
// GB/T 15821.1-2020 MAC scheme 6
|
// implements MAC with the given block cipher. The padding scheme is ISO/IEC 9797-1 method 2.
|
||||||
func NewLMAC(creator func(key []byte) (cipher.Block, error), key []byte, size int) BockCipherMAC {
|
func NewLMAC(creator func(key []byte) (cipher.Block, error), key []byte, size int) BlockCipherMAC {
|
||||||
|
return NewLMACWithPadding(creator, key, size, padding.NewISO9797M2Padding)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLMACWithPadding creates a new LMAC (Length-based Message Authentication Code) with padding.
|
||||||
|
func NewLMACWithPadding(creator func(key []byte) (cipher.Block, error), key []byte, size int, newPaddingFunc padding.NewPaddingFunc) BlockCipherMAC {
|
||||||
var b, b1, b2 cipher.Block
|
var b, b1, b2 cipher.Block
|
||||||
var err error
|
var err error
|
||||||
if b, err = creator(key); err != nil {
|
if b, err = creator(key); err != nil {
|
||||||
@ -359,7 +382,7 @@ func NewLMAC(creator func(key []byte) (cipher.Block, error), key []byte, size in
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &lmac{b1: b1, b2: b2, pad: padding.NewISO9797M2Padding(uint(blockSize)), size: size}
|
return &lmac{b1: b1, b2: b2, pad: newPaddingFunc(uint(blockSize)), size: size}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lmac) Size() int {
|
func (l *lmac) Size() int {
|
||||||
@ -385,11 +408,11 @@ type trCBCMAC struct {
|
|||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTRCBCMAC returns a TR-CBC-MAC instance that implements MAC with the given block cipher.
|
// NewTRCBCMAC returns a TR-CBC-MAC (GB/T 15821.1-2020 MAC scheme 7) instance that
|
||||||
// GB/T 15821.1-2020 MAC scheme 7
|
// implements MAC with the given block cipher.
|
||||||
//
|
//
|
||||||
// Reference: TrCBC: Another look at CBC-MAC.
|
// Reference: TrCBC: Another look at CBC-MAC.
|
||||||
func NewTRCBCMAC(b cipher.Block, size int) BockCipherMAC {
|
func NewTRCBCMAC(b cipher.Block, size int) BlockCipherMAC {
|
||||||
if size <= 0 || size > b.BlockSize() {
|
if size <= 0 || size > b.BlockSize() {
|
||||||
panic("cbcmac: invalid size")
|
panic("cbcmac: invalid size")
|
||||||
}
|
}
|
||||||
@ -425,11 +448,10 @@ type cbcrMAC struct {
|
|||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCBCRMAC returns a CBCRMAC instance that implements MAC with the given block cipher.
|
// NewCBCRMAC returns a CBCRMAC (GB/T 15821.1-2020 MAC scheme 8) instance that implements MAC with the given block cipher.
|
||||||
// GB/T 15821.1-2020 MAC scheme 8
|
|
||||||
//
|
//
|
||||||
// Reference: CBCR: CBC MAC with rotating transformations.
|
// Reference: CBCR: CBC MAC with rotating transformations.
|
||||||
func NewCBCRMAC(b cipher.Block, size int) BockCipherMAC {
|
func NewCBCRMAC(b cipher.Block, size int) BlockCipherMAC {
|
||||||
if size <= 0 || size > b.BlockSize() {
|
if size <= 0 || size > b.BlockSize() {
|
||||||
panic("cbcmac: invalid size")
|
panic("cbcmac: invalid size")
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/internal/cryptotest"
|
"github.com/emmansun/gmsm/internal/cryptotest"
|
||||||
|
"github.com/emmansun/gmsm/padding"
|
||||||
"github.com/emmansun/gmsm/sm4"
|
"github.com/emmansun/gmsm/sm4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -48,6 +49,114 @@ func TestCBCMAC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCBCMACWithPadding(t *testing.T) {
|
||||||
|
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
||||||
|
cases := []struct {
|
||||||
|
key []byte
|
||||||
|
src []byte
|
||||||
|
tag []byte
|
||||||
|
newPaddingFunc padding.NewPaddingFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
nil,
|
||||||
|
[]byte{0x8c, 0x33, 0x8e, 0x5a, 0x27, 0xe3, 0x49, 0xbe, 0xae, 0x39, 0x21, 0x4f, 0xed, 0xa9, 0x70, 0x99},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte("This is the test message for mac"),
|
||||||
|
[]byte{0x4b, 0x65, 0x53, 0xaf, 0x3c, 0x4e, 0x27, 0x44, 0x84, 0x12, 0x31, 0x5a, 0xc7, 0x84, 0x95, 0x35},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte("This is the test message "),
|
||||||
|
[]byte{0x42, 0x1a, 0xd1, 0x69, 0x0a, 0xa1, 0x52, 0xe2, 0x84, 0x6f, 0xa2, 0xa5, 0xd8, 0x34, 0x45, 0xa9},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte("This is the test message for mac"),
|
||||||
|
[]byte{0x71, 0xaf, 0x7e, 0x45, 0x53, 0x40, 0x4c, 0xbc, 0xc4, 0xf2, 0x97, 0x3c, 0xdb, 0xd0, 0xf0, 0x63},
|
||||||
|
padding.NewISO9797M3Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte("This is the test message "),
|
||||||
|
[]byte{0x6a, 0x4a, 0x86, 0xf5, 0xb5, 0xe4, 0x68, 0xda, 0xd2, 0x7d, 0xf2, 0x5f, 0xb9, 0xd9, 0xbe, 0x16},
|
||||||
|
padding.NewISO9797M3Padding,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range cases {
|
||||||
|
block, err := sm4.NewCipher(c.key)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("#%d: failed to create cipher: %v", i, err)
|
||||||
|
}
|
||||||
|
mac := NewCBCMACWithPadding(block, len(c.tag), c.newPaddingFunc)
|
||||||
|
tag := mac.MAC(c.src)
|
||||||
|
if !bytes.Equal(tag, c.tag) {
|
||||||
|
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEMACWithPadding(t *testing.T) {
|
||||||
|
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
||||||
|
cases := []struct {
|
||||||
|
key1 []byte
|
||||||
|
key2 []byte
|
||||||
|
src []byte
|
||||||
|
tag []byte
|
||||||
|
newPaddingFunc padding.NewPaddingFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
nil,
|
||||||
|
[]byte{0x2c, 0xf6, 0xed, 0xf6, 0x3c, 0xce, 0x14, 0x44, 0x89, 0xea, 0xdd, 0xf0, 0x7b, 0x49, 0x38, 0xdb},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message for mac"),
|
||||||
|
[]byte{0xe4, 0x23, 0xe3, 0x55, 0x99, 0xaf, 0xd9, 0x48, 0xae, 0xc5, 0x0b, 0xde, 0xe8, 0x38, 0xe9, 0xea},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message "),
|
||||||
|
[]byte{0xf0, 0x26, 0x25, 0xce, 0xad, 0x00, 0x8d, 0x4e, 0xfb, 0xf3, 0xf0, 0xb2, 0xb0, 0xc2, 0xa7, 0x5b},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message for mac"),
|
||||||
|
[]byte{0x40, 0x03, 0xba, 0x1b, 0x6a, 0xdc, 0x53, 0xa8, 0x26, 0xe8, 0x2f, 0xce, 0xa1, 0x6a, 0xfa, 0xac},
|
||||||
|
padding.NewISO9797M3Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message "),
|
||||||
|
[]byte{0xff, 0xd5, 0xf1, 0xf2, 0xe5, 0xed, 0xa5, 0xcb, 0xf4, 0x02, 0xd6, 0x5a, 0x5b, 0x0b, 0x19, 0x53},
|
||||||
|
padding.NewISO9797M3Padding,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range cases {
|
||||||
|
mac := NewEMACWithPadding(sm4.NewCipher, c.key1, c.key2, len(c.tag), c.newPaddingFunc)
|
||||||
|
tag := mac.MAC(c.src)
|
||||||
|
if !bytes.Equal(tag, c.tag) {
|
||||||
|
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestEMAC(t *testing.T) {
|
func TestEMAC(t *testing.T) {
|
||||||
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@ -122,6 +231,61 @@ func TestANSIRetailMAC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestANSIRetailMACWithPadding(t *testing.T) {
|
||||||
|
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
||||||
|
cases := []struct {
|
||||||
|
key1 []byte
|
||||||
|
key2 []byte
|
||||||
|
src []byte
|
||||||
|
tag []byte
|
||||||
|
newPaddingFunc padding.NewPaddingFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
nil,
|
||||||
|
[]byte{0xb4, 0x73, 0x6b, 0xe9, 0xa1, 0x74, 0xfa, 0xa3, 0x4d, 0xb1, 0xe9, 0xf1, 0xda, 0xcd, 0x5d, 0x62},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message for mac"),
|
||||||
|
[]byte{0x51, 0xe9, 0x92, 0x8c, 0x22, 0x38, 0x33, 0x0c, 0x32, 0x31, 0xb8, 0x75, 0x2a, 0x9a, 0xfd, 0x7f},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message "),
|
||||||
|
[]byte{0x19, 0x72, 0x47, 0x22, 0x9c, 0xe9, 0xd7, 0xb6, 0xae, 0x40, 0x5b, 0xf8, 0x85, 0xb2, 0x70, 0x57},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message for mac"),
|
||||||
|
[]byte{0x7c, 0xd4, 0x8c, 0x42, 0x42, 0xe4, 0x55, 0x75, 0xe5, 0x1a, 0xaf, 0x0d, 0xcc, 0x7a, 0x20, 0x8c},
|
||||||
|
padding.NewISO9797M3Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message "),
|
||||||
|
[]byte{0x3c, 0x43, 0x0f, 0x1e, 0xa4, 0x3b, 0x54, 0x0c, 0x68, 0x45, 0x7e, 0x24, 0x9c, 0x46, 0xf1, 0xdb},
|
||||||
|
padding.NewISO9797M3Padding,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range cases {
|
||||||
|
mac := NewANSIRetailMACWithPadding(sm4.NewCipher, c.key1, c.key2, len(c.tag), c.newPaddingFunc)
|
||||||
|
tag := mac.MAC(c.src)
|
||||||
|
if !bytes.Equal(tag, c.tag) {
|
||||||
|
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMACDES(t *testing.T) {
|
func TestMACDES(t *testing.T) {
|
||||||
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@ -159,6 +323,61 @@ func TestMACDES(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMACDESWithPadding(t *testing.T) {
|
||||||
|
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
||||||
|
cases := []struct {
|
||||||
|
key1 []byte
|
||||||
|
key2 []byte
|
||||||
|
src []byte
|
||||||
|
tag []byte
|
||||||
|
newPaddingFunc padding.NewPaddingFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
nil,
|
||||||
|
[]byte{0x0c, 0x56, 0x00, 0x96, 0xb6, 0x09, 0xed, 0x0e, 0xaa, 0x39, 0xaf, 0xd6, 0xe2, 0x66, 0x65, 0x11},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message for mac"),
|
||||||
|
[]byte{0x7e, 0x1a, 0x9a, 0x5e, 0x0e, 0xf0, 0x94, 0x7f, 0x25, 0xcb, 0x94, 0x85, 0x26, 0x1c, 0x98, 0x5c},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message "),
|
||||||
|
[]byte{0x94, 0x94, 0x76, 0xd3, 0x5f, 0x17, 0x26, 0x1e, 0x1f, 0xb8, 0xc4, 0x39, 0x6d, 0x62, 0xdc, 0x05},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message for mac"),
|
||||||
|
[]byte{0x28, 0xa7, 0x0d, 0x6b, 0xcc, 0xf7, 0x44, 0x22, 0x46, 0x20, 0x58, 0xab, 0xbc, 0x27, 0xf6, 0xae},
|
||||||
|
padding.NewISO9797M3Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
|
||||||
|
[]byte("This is the test message "),
|
||||||
|
[]byte{0xc9, 0xd3, 0x4e, 0x16, 0xc4, 0x9a, 0xb6, 0x43, 0x57, 0xa2, 0x61, 0x8d, 0xeb, 0xd1, 0x03, 0x2f},
|
||||||
|
padding.NewISO9797M3Padding,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range cases {
|
||||||
|
mac := NewMACDESWithPadding(sm4.NewCipher, c.key1, c.key2, 16, c.newPaddingFunc)
|
||||||
|
tag := mac.MAC(c.src)
|
||||||
|
if !bytes.Equal(tag, c.tag) {
|
||||||
|
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCMAC(t *testing.T) {
|
func TestCMAC(t *testing.T) {
|
||||||
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@ -229,6 +448,55 @@ func TestLMAC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLMACWithPadding(t *testing.T) {
|
||||||
|
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
||||||
|
cases := []struct {
|
||||||
|
key []byte
|
||||||
|
src []byte
|
||||||
|
tag []byte
|
||||||
|
newPaddingFunc padding.NewPaddingFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
nil,
|
||||||
|
[]byte{0xcd, 0x7e, 0xd2, 0x79, 0x64, 0xe2, 0x57, 0xc0, 0x77, 0xf0, 0x55, 0xf8, 0xee, 0x38, 0x3c, 0x3f},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte("This is the test message for mac"),
|
||||||
|
[]byte{0xa0, 0xc4, 0x65, 0xee, 0x58, 0x96, 0x97, 0x2f, 0x83, 0x37, 0xaa, 0x1f, 0x92, 0xc9, 0x9d, 0x10},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte("This is the test message "),
|
||||||
|
[]byte{0x60, 0xdd, 0x95, 0x5e, 0xd0, 0xca, 0x3d, 0x7a, 0x64, 0x22, 0x71, 0x74, 0xdd, 0x98, 0xdd, 0x81},
|
||||||
|
padding.NewISO9797M2Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte("This is the test message for mac"),
|
||||||
|
[]byte{0x43, 0x05, 0x0d, 0x51, 0xc6, 0x56, 0xae, 0x60, 0xbe, 0x27, 0x3f, 0xbe, 0xa4, 0x87, 0x0e, 0xf1},
|
||||||
|
padding.NewISO9797M3Padding,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
|
||||||
|
[]byte("This is the test message "),
|
||||||
|
[]byte{0x61, 0xe0, 0x00, 0x49, 0xe2, 0x69, 0x62, 0xa3, 0x6f, 0xed, 0xba, 0x8d, 0x4f, 0x52, 0xf0, 0xad},
|
||||||
|
padding.NewISO9797M3Padding,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range cases {
|
||||||
|
mac := NewLMACWithPadding(sm4.NewCipher, c.key, 16, c.newPaddingFunc)
|
||||||
|
tag := mac.MAC(c.src)
|
||||||
|
if !bytes.Equal(tag, c.tag) {
|
||||||
|
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTRCBCMAC(t *testing.T) {
|
func TestTRCBCMAC(t *testing.T) {
|
||||||
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
// Test vectors from GB/T 15821.1-2020 Appendix B.
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
@ -22,14 +23,24 @@ func TestCreateCertificateRequest(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
certRSAKey, err := rsa.GenerateKey(random, 2048)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
tmpKey, err := sm2.GenerateKey(random)
|
tmpKey, err := sm2.GenerateKey(random)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
invalidTmpKey, err := ecdsa.GenerateKey(elliptic.P256(), random)
|
p256Key, err := ecdsa.GenerateKey(elliptic.P256(), random)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rsaKey, err := rsa.GenerateKey(random, 2048)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
template := &x509.CertificateRequest{
|
template := &x509.CertificateRequest{
|
||||||
Subject: pkix.Name{
|
Subject: pkix.Name{
|
||||||
CommonName: "certRequisition",
|
CommonName: "certRequisition",
|
||||||
@ -37,41 +48,110 @@ func TestCreateCertificateRequest(t *testing.T) {
|
|||||||
Country: []string{"CN"},
|
Country: []string{"CN"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = CreateCertificateRequest(random, template, "", "", "")
|
|
||||||
if err == nil || err.Error() != "x509: certificate private key does not implement crypto.Signer" {
|
testCases := []struct {
|
||||||
t.Fatalf("expect certificate private key does not implement crypto.Signer, got %v", err)
|
template *x509.CertificateRequest
|
||||||
|
priv interface{}
|
||||||
|
tmpPub interface{}
|
||||||
|
challengePassword string
|
||||||
|
wantErr bool
|
||||||
|
errormsg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
template: template,
|
||||||
|
priv: certKey,
|
||||||
|
tmpPub: tmpKey.Public(),
|
||||||
|
challengePassword: "111111",
|
||||||
|
wantErr: false,
|
||||||
|
errormsg: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template: template,
|
||||||
|
priv: certRSAKey,
|
||||||
|
tmpPub: rsaKey.Public(),
|
||||||
|
challengePassword: "111111",
|
||||||
|
wantErr: false,
|
||||||
|
errormsg: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template: template,
|
||||||
|
priv: p256Key,
|
||||||
|
tmpPub: nil,
|
||||||
|
challengePassword: "",
|
||||||
|
wantErr: false,
|
||||||
|
errormsg: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template: template,
|
||||||
|
priv: "",
|
||||||
|
tmpPub: "",
|
||||||
|
challengePassword: "",
|
||||||
|
wantErr: true,
|
||||||
|
errormsg: "x509: certificate private key does not implement crypto.Signer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template: template,
|
||||||
|
priv: certKey,
|
||||||
|
tmpPub: "",
|
||||||
|
challengePassword: "",
|
||||||
|
wantErr: true,
|
||||||
|
errormsg: "x509: SM2 temp public key is required",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template: template,
|
||||||
|
priv: certKey,
|
||||||
|
tmpPub: rsaKey.Public(),
|
||||||
|
challengePassword: "",
|
||||||
|
wantErr: true,
|
||||||
|
errormsg: "x509: SM2 temp public key is required",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template: template,
|
||||||
|
priv: certRSAKey,
|
||||||
|
tmpPub: tmpKey.Public(),
|
||||||
|
challengePassword: "",
|
||||||
|
wantErr: true,
|
||||||
|
errormsg: "x509: RSA temp public key is required",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template: template,
|
||||||
|
priv: certKey,
|
||||||
|
tmpPub: p256Key.Public(),
|
||||||
|
challengePassword: "",
|
||||||
|
wantErr: true,
|
||||||
|
errormsg: "x509: SM2 temp public key is required",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template: template,
|
||||||
|
priv: p256Key,
|
||||||
|
tmpPub: certKey.Public(),
|
||||||
|
challengePassword: "111111",
|
||||||
|
wantErr: true,
|
||||||
|
errormsg: "x509: only RSA or SM2 key is supported",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template: template,
|
||||||
|
priv: certKey,
|
||||||
|
tmpPub: tmpKey.Public(),
|
||||||
|
challengePassword: "",
|
||||||
|
wantErr: true,
|
||||||
|
errormsg: "x509: challenge password is required",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
_, err = CreateCertificateRequest(random, template, certKey, "", "")
|
for _, tc := range testCases {
|
||||||
if err == nil || err.Error() != "x509: only SM2 public key is supported" {
|
_, err := CreateCertificateRequest(random, tc.template, tc.priv, tc.tmpPub, tc.challengePassword)
|
||||||
t.Fatalf("expect only SM2 public key is supported, got %v", err)
|
if tc.wantErr {
|
||||||
}
|
if err == nil {
|
||||||
_, err = CreateCertificateRequest(random, template, certKey, invalidTmpKey.Public(), "")
|
t.Fatal("expected error, got nil")
|
||||||
if err == nil || err.Error() != "x509: only SM2 public key is supported" {
|
}
|
||||||
t.Fatalf("expect only SM2 public key is supported, got %v", err)
|
if err.Error() != tc.errormsg {
|
||||||
}
|
t.Fatalf("expected error %s, got %s", tc.errormsg, err.Error())
|
||||||
_, err = CreateCertificateRequest(random, template, certKey, tmpKey.Public(), "")
|
}
|
||||||
if err == nil || err.Error() != "x509: challenge password is required" {
|
} else {
|
||||||
t.Fatalf("expect challenge password is required, got %v", err)
|
if err != nil {
|
||||||
}
|
t.Fatal(err)
|
||||||
csrDer, err := CreateCertificateRequest(random, template, certKey, tmpKey.Public(), "111111")
|
}
|
||||||
if err != nil {
|
}
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
csr, err := ParseCertificateRequest(csrDer)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if csr.Subject.CommonName != "certRequisition" {
|
|
||||||
t.Fatal("common name not match")
|
|
||||||
}
|
|
||||||
if csr.Subject.CommonName != "certRequisition" {
|
|
||||||
t.Fatal("common name not match")
|
|
||||||
}
|
|
||||||
if csr.ChallengePassword != "111111" {
|
|
||||||
t.Fatal("challenge password not match")
|
|
||||||
}
|
|
||||||
if !tmpKey.PublicKey.Equal(csr.TmpPublicKey) {
|
|
||||||
t.Fatal("tmp public key not match")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
cipher/bc.go
24
cipher/bc.go
@ -3,25 +3,23 @@
|
|||||||
package cipher
|
package cipher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_cipher "crypto/cipher"
|
"bytes"
|
||||||
|
"crypto/cipher"
|
||||||
"github.com/emmansun/gmsm/internal/subtle"
|
"crypto/subtle"
|
||||||
)
|
)
|
||||||
|
|
||||||
type bc struct {
|
type bc struct {
|
||||||
b _cipher.Block
|
b cipher.Block
|
||||||
blockSize int
|
blockSize int
|
||||||
iv []byte
|
iv []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBC(b _cipher.Block, iv []byte) *bc {
|
func newBC(b cipher.Block, iv []byte) *bc {
|
||||||
c := &bc{
|
return &bc{
|
||||||
b: b,
|
b: b,
|
||||||
blockSize: b.BlockSize(),
|
blockSize: b.BlockSize(),
|
||||||
iv: make([]byte, b.BlockSize()),
|
iv: bytes.Clone(iv),
|
||||||
}
|
}
|
||||||
copy(c.iv, iv)
|
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type bcEncrypter bc
|
type bcEncrypter bc
|
||||||
@ -31,13 +29,13 @@ type bcEncrypter bc
|
|||||||
// NewBCEncrypter will check for this interface and return the specific
|
// NewBCEncrypter will check for this interface and return the specific
|
||||||
// BlockMode if found.
|
// BlockMode if found.
|
||||||
type bcEncAble interface {
|
type bcEncAble interface {
|
||||||
NewBCEncrypter(iv []byte) _cipher.BlockMode
|
NewBCEncrypter(iv []byte) cipher.BlockMode
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBCEncrypter returns a BlockMode which encrypts in block chaining
|
// NewBCEncrypter returns a BlockMode which encrypts in block chaining
|
||||||
// mode, using the given Block. The length of iv must be the same as the
|
// mode, using the given Block. The length of iv must be the same as the
|
||||||
// Block's block size.
|
// Block's block size.
|
||||||
func NewBCEncrypter(b _cipher.Block, iv []byte) _cipher.BlockMode {
|
func NewBCEncrypter(b cipher.Block, iv []byte) cipher.BlockMode {
|
||||||
if len(iv) != b.BlockSize() {
|
if len(iv) != b.BlockSize() {
|
||||||
panic("cipher.NewBCEncrypter: IV length must equal block size")
|
panic("cipher.NewBCEncrypter: IV length must equal block size")
|
||||||
}
|
}
|
||||||
@ -82,13 +80,13 @@ type bcDecrypter bc
|
|||||||
// NewBCDecrypter will check for this interface and return the specific
|
// NewBCDecrypter will check for this interface and return the specific
|
||||||
// BlockMode if found.
|
// BlockMode if found.
|
||||||
type bcDecAble interface {
|
type bcDecAble interface {
|
||||||
NewBCDecrypter(iv []byte) _cipher.BlockMode
|
NewBCDecrypter(iv []byte) cipher.BlockMode
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBCDecrypter returns a BlockMode which decrypts in block chaining
|
// NewBCDecrypter returns a BlockMode which decrypts in block chaining
|
||||||
// mode, using the given Block. The length of iv must be the same as the
|
// mode, using the given Block. The length of iv must be the same as the
|
||||||
// Block's block size and must match the iv used to encrypt the data.
|
// Block's block size and must match the iv used to encrypt the data.
|
||||||
func NewBCDecrypter(b _cipher.Block, iv []byte) _cipher.BlockMode {
|
func NewBCDecrypter(b cipher.Block, iv []byte) cipher.BlockMode {
|
||||||
if len(iv) != b.BlockSize() {
|
if len(iv) != b.BlockSize() {
|
||||||
panic("cipher.NewBCDecrypter: IV length must equal block size")
|
panic("cipher.NewBCDecrypter: IV length must equal block size")
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,14 @@
|
|||||||
package cipher
|
package cipher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
goCipher "crypto/cipher"
|
"crypto/cipher"
|
||||||
goSubtle "crypto/subtle"
|
"crypto/subtle"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/internal/alias"
|
"github.com/emmansun/gmsm/internal/alias"
|
||||||
"github.com/emmansun/gmsm/internal/byteorder"
|
"github.com/emmansun/gmsm/internal/byteorder"
|
||||||
"github.com/emmansun/gmsm/internal/subtle"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -23,11 +22,11 @@ const (
|
|||||||
// ccmAble is an interface implemented by ciphers that have a specific optimized
|
// ccmAble is an interface implemented by ciphers that have a specific optimized
|
||||||
// implementation of CCM.
|
// implementation of CCM.
|
||||||
type ccmAble interface {
|
type ccmAble interface {
|
||||||
NewCCM(nonceSize, tagSize int) (goCipher.AEAD, error)
|
NewCCM(nonceSize, tagSize int) (cipher.AEAD, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ccm struct {
|
type ccm struct {
|
||||||
cipher goCipher.Block
|
cipher cipher.Block
|
||||||
nonceSize int
|
nonceSize int
|
||||||
tagSize int
|
tagSize int
|
||||||
}
|
}
|
||||||
@ -57,14 +56,14 @@ func maxlen(L, tagsize int) int {
|
|||||||
|
|
||||||
// NewCCM returns the given 128-bit, block cipher wrapped in CCM
|
// NewCCM returns the given 128-bit, block cipher wrapped in CCM
|
||||||
// with the standard nonce length.
|
// with the standard nonce length.
|
||||||
func NewCCM(cipher goCipher.Block) (goCipher.AEAD, error) {
|
func NewCCM(cipher cipher.Block) (cipher.AEAD, error) {
|
||||||
return NewCCMWithNonceAndTagSize(cipher, ccmStandardNonceSize, ccmTagSize)
|
return NewCCMWithNonceAndTagSize(cipher, ccmStandardNonceSize, ccmTagSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCCMWithNonceSize returns the given 128-bit, block cipher wrapped in CCM,
|
// NewCCMWithNonceSize returns the given 128-bit, block cipher wrapped in CCM,
|
||||||
// which accepts nonces of the given length. The length must not
|
// which accepts nonces of the given length. The length must not
|
||||||
// be zero.
|
// be zero.
|
||||||
func NewCCMWithNonceSize(cipher goCipher.Block, size int) (goCipher.AEAD, error) {
|
func NewCCMWithNonceSize(cipher cipher.Block, size int) (cipher.AEAD, error) {
|
||||||
return NewCCMWithNonceAndTagSize(cipher, size, ccmTagSize)
|
return NewCCMWithNonceAndTagSize(cipher, size, ccmTagSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,12 +71,12 @@ func NewCCMWithNonceSize(cipher goCipher.Block, size int) (goCipher.AEAD, error)
|
|||||||
// which generates tags with the given length.
|
// which generates tags with the given length.
|
||||||
//
|
//
|
||||||
// Tag sizes between 8 and 16 bytes are allowed.
|
// Tag sizes between 8 and 16 bytes are allowed.
|
||||||
func NewCCMWithTagSize(cipher goCipher.Block, tagSize int) (goCipher.AEAD, error) {
|
func NewCCMWithTagSize(cipher cipher.Block, tagSize int) (cipher.AEAD, error) {
|
||||||
return NewCCMWithNonceAndTagSize(cipher, ccmStandardNonceSize, tagSize)
|
return NewCCMWithNonceAndTagSize(cipher, ccmStandardNonceSize, tagSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://tools.ietf.org/html/rfc3610
|
// https://tools.ietf.org/html/rfc3610
|
||||||
func NewCCMWithNonceAndTagSize(cipher goCipher.Block, nonceSize, tagSize int) (goCipher.AEAD, error) {
|
func NewCCMWithNonceAndTagSize(cipher cipher.Block, nonceSize, tagSize int) (cipher.AEAD, error) {
|
||||||
if tagSize < ccmMinimumTagSize || tagSize > ccmBlockSize || tagSize&1 != 0 {
|
if tagSize < ccmMinimumTagSize || tagSize > ccmBlockSize || tagSize&1 != 0 {
|
||||||
return nil, errors.New("cipher: incorrect tag size given to CCM")
|
return nil, errors.New("cipher: incorrect tag size given to CCM")
|
||||||
}
|
}
|
||||||
@ -189,7 +188,7 @@ func (c *ccm) Seal(dst, nonce, plaintext, data []byte) []byte {
|
|||||||
c.cipher.Encrypt(tagMask[:], counter[:])
|
c.cipher.Encrypt(tagMask[:], counter[:])
|
||||||
|
|
||||||
counter[len(counter)-1] |= 1
|
counter[len(counter)-1] |= 1
|
||||||
ctr := goCipher.NewCTR(c.cipher, counter[:])
|
ctr := cipher.NewCTR(c.cipher, counter[:])
|
||||||
ctr.XORKeyStream(out, plaintext)
|
ctr.XORKeyStream(out, plaintext)
|
||||||
|
|
||||||
tag := c.auth(nonce, plaintext, data, &tagMask)
|
tag := c.auth(nonce, plaintext, data, &tagMask)
|
||||||
@ -231,17 +230,15 @@ func (c *ccm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
counter[len(counter)-1] |= 1
|
counter[len(counter)-1] |= 1
|
||||||
ctr := goCipher.NewCTR(c.cipher, counter[:])
|
ctr := cipher.NewCTR(c.cipher, counter[:])
|
||||||
ctr.XORKeyStream(out, ciphertext)
|
ctr.XORKeyStream(out, ciphertext)
|
||||||
expectedTag := c.auth(nonce, out, data, &tagMask)
|
expectedTag := c.auth(nonce, out, data, &tagMask)
|
||||||
if goSubtle.ConstantTimeCompare(expectedTag, tag) != 1 {
|
if subtle.ConstantTimeCompare(expectedTag, tag) != 1 {
|
||||||
// The AESNI code decrypts and authenticates concurrently, and
|
// The AESNI code decrypts and authenticates concurrently, and
|
||||||
// so overwrites dst in the event of a tag mismatch. That
|
// so overwrites dst in the event of a tag mismatch. That
|
||||||
// behavior is mimicked here in order to be consistent across
|
// behavior is mimicked here in order to be consistent across
|
||||||
// platforms.
|
// platforms.
|
||||||
for i := range out {
|
clear(out)
|
||||||
out[i] = 0
|
|
||||||
}
|
|
||||||
return nil, errOpen
|
return nil, errOpen
|
||||||
}
|
}
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
14
cipher/common.go
Normal file
14
cipher/common.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package cipher
|
||||||
|
|
||||||
|
import "crypto/cipher"
|
||||||
|
|
||||||
|
// blockSize is the block size that the underlying cipher must have.
|
||||||
|
const blockSize = 16
|
||||||
|
|
||||||
|
type concurrentBlocks interface {
|
||||||
|
Concurrency() int
|
||||||
|
EncryptBlocks(dst, src []byte)
|
||||||
|
DecryptBlocks(dst, src []byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CipherCreator func([]byte) (cipher.Block, error)
|
@ -1,12 +1,12 @@
|
|||||||
package cipher
|
package cipher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_cipher "crypto/cipher"
|
"crypto/cipher"
|
||||||
|
"crypto/subtle"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/internal/alias"
|
"github.com/emmansun/gmsm/internal/alias"
|
||||||
"github.com/emmansun/gmsm/internal/byteorder"
|
"github.com/emmansun/gmsm/internal/byteorder"
|
||||||
"github.com/emmansun/gmsm/internal/subtle"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// A LengthPreservingMode represents a block cipher running in a length preserving mode (HCTR,
|
// A LengthPreservingMode represents a block cipher running in a length preserving mode (HCTR,
|
||||||
@ -105,7 +105,7 @@ var hctrReductionTable = []uint16{
|
|||||||
// https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.470.5288
|
// https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.470.5288
|
||||||
// GB/T 17964-2021 第11章 带泛杂凑函数的计数器工作模式
|
// GB/T 17964-2021 第11章 带泛杂凑函数的计数器工作模式
|
||||||
type hctr struct {
|
type hctr struct {
|
||||||
cipher _cipher.Block
|
cipher cipher.Block
|
||||||
tweak [blockSize]byte
|
tweak [blockSize]byte
|
||||||
// productTable contains the first sixteen powers of the hash key.
|
// productTable contains the first sixteen powers of the hash key.
|
||||||
// However, they are in bit reversed order.
|
// However, they are in bit reversed order.
|
||||||
@ -118,7 +118,7 @@ func (h *hctr) BlockSize() int {
|
|||||||
|
|
||||||
// NewHCTR returns a [LengthPreservingMode] which encrypts/decrypts useing the given [Block]
|
// NewHCTR returns a [LengthPreservingMode] which encrypts/decrypts useing the given [Block]
|
||||||
// in HCTR mode. The lenght of tweak and hash key must be the same as the [Block]'s block size.
|
// in HCTR mode. The lenght of tweak and hash key must be the same as the [Block]'s block size.
|
||||||
func NewHCTR(cipher _cipher.Block, tweak, hkey []byte) (LengthPreservingMode, error) {
|
func NewHCTR(cipher cipher.Block, tweak, hkey []byte) (LengthPreservingMode, error) {
|
||||||
if len(tweak) != blockSize || len(hkey) != blockSize {
|
if len(tweak) != blockSize || len(hkey) != blockSize {
|
||||||
return nil, errors.New("cipher: invalid tweak and/or hash key length")
|
return nil, errors.New("cipher: invalid tweak and/or hash key length")
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
package cipher
|
package cipher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
_cipher "crypto/cipher"
|
_cipher "crypto/cipher"
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
@ -28,8 +29,8 @@ func newOFBNLF(cipherFunc CipherCreator, key, iv []byte) (*ofbnlf, error) {
|
|||||||
if len(iv) != c.blockSize {
|
if len(iv) != c.blockSize {
|
||||||
return nil, errors.New("cipher: IV length must equal block size")
|
return nil, errors.New("cipher: IV length must equal block size")
|
||||||
}
|
}
|
||||||
c.iv = make([]byte, c.blockSize)
|
c.iv = bytes.Clone(iv)
|
||||||
copy(c.iv, iv)
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
313
cipher/xts.go
313
cipher/xts.go
@ -1,54 +1,21 @@
|
|||||||
package cipher
|
package cipher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_cipher "crypto/cipher"
|
"crypto/cipher"
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/internal/alias"
|
|
||||||
"github.com/emmansun/gmsm/internal/byteorder"
|
"github.com/emmansun/gmsm/internal/byteorder"
|
||||||
"github.com/emmansun/gmsm/internal/subtle"
|
"github.com/emmansun/gmsm/internal/cipher/xts"
|
||||||
)
|
)
|
||||||
|
|
||||||
const GF128_FDBK byte = 0x87
|
|
||||||
|
|
||||||
type CipherCreator func([]byte) (_cipher.Block, error)
|
|
||||||
|
|
||||||
type concurrentBlocks interface {
|
|
||||||
Concurrency() int
|
|
||||||
EncryptBlocks(dst, src []byte)
|
|
||||||
DecryptBlocks(dst, src []byte)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cipher contains an expanded key structure. It is unsafe for concurrent use.
|
|
||||||
type xts struct {
|
|
||||||
b _cipher.Block
|
|
||||||
tweak [blockSize]byte
|
|
||||||
isGB bool // if true, follows GB/T 17964-2021
|
|
||||||
}
|
|
||||||
|
|
||||||
// blockSize is the block size that the underlying cipher must have. XTS is
|
|
||||||
// only defined for 16-byte ciphers.
|
|
||||||
const blockSize = 16
|
|
||||||
|
|
||||||
type xtsEncrypter xts
|
|
||||||
|
|
||||||
// xtsEncAble is an interface implemented by ciphers that have a specific
|
|
||||||
// optimized implementation of XTS encryption, like sm4.
|
|
||||||
// NewXTSEncrypter will check for this interface and return the specific
|
|
||||||
// BlockMode if found.
|
|
||||||
type xtsEncAble interface {
|
|
||||||
NewXTSEncrypter(encryptedTweak *[blockSize]byte, isGB bool) _cipher.BlockMode
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewXTSEncrypter creates a Cipher given a function for creating the underlying
|
// NewXTSEncrypter creates a Cipher given a function for creating the underlying
|
||||||
// block cipher (which must have a block size of 16 bytes).
|
// block cipher (which must have a block size of 16 bytes).
|
||||||
func NewXTSEncrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (_cipher.BlockMode, error) {
|
func NewXTSEncrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (cipher.BlockMode, error) {
|
||||||
return newXTSEncrypter(cipherFunc, key, tweakKey, tweak, false)
|
return xts.NewXTSEncrypter(cipherFunc, key, tweakKey, tweak, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewXTSEncrypterWithSector creates a Cipher given a function for creating the underlying
|
// NewXTSEncrypterWithSector creates a Cipher given a function for creating the underlying
|
||||||
// block cipher (which must have a block size of 16 bytes) with sector number.
|
// block cipher (which must have a block size of 16 bytes) with sector number.
|
||||||
func NewXTSEncrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (_cipher.BlockMode, error) {
|
func NewXTSEncrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (cipher.BlockMode, error) {
|
||||||
tweak := make([]byte, blockSize)
|
tweak := make([]byte, blockSize)
|
||||||
byteorder.LEPutUint64(tweak[:8], sectorNum)
|
byteorder.LEPutUint64(tweak[:8], sectorNum)
|
||||||
return NewXTSEncrypter(cipherFunc, key, tweakKey, tweak)
|
return NewXTSEncrypter(cipherFunc, key, tweakKey, tweak)
|
||||||
@ -57,70 +24,28 @@ func NewXTSEncrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, s
|
|||||||
// NewGBXTSEncrypter creates a Cipher given a function for creating the underlying
|
// NewGBXTSEncrypter creates a Cipher given a function for creating the underlying
|
||||||
// block cipher (which must have a block size of 16 bytes).
|
// block cipher (which must have a block size of 16 bytes).
|
||||||
// It follows GB/T 17964-2021.
|
// It follows GB/T 17964-2021.
|
||||||
func NewGBXTSEncrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (_cipher.BlockMode, error) {
|
func NewGBXTSEncrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (cipher.BlockMode, error) {
|
||||||
return newXTSEncrypter(cipherFunc, key, tweakKey, tweak, true)
|
return xts.NewXTSEncrypter(cipherFunc, key, tweakKey, tweak, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGBXTSEncrypterWithSector creates a Cipher given a function for creating the underlying
|
// NewGBXTSEncrypterWithSector creates a Cipher given a function for creating the underlying
|
||||||
// block cipher (which must have a block size of 16 bytes) with sector number.
|
// block cipher (which must have a block size of 16 bytes) with sector number.
|
||||||
// It follows GB/T 17964-2021.
|
// It follows GB/T 17964-2021.
|
||||||
func NewGBXTSEncrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (_cipher.BlockMode, error) {
|
func NewGBXTSEncrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (cipher.BlockMode, error) {
|
||||||
tweak := make([]byte, blockSize)
|
tweak := make([]byte, blockSize)
|
||||||
byteorder.LEPutUint64(tweak[:8], sectorNum)
|
byteorder.LEPutUint64(tweak[:8], sectorNum)
|
||||||
return NewGBXTSEncrypter(cipherFunc, key, tweakKey, tweak)
|
return NewGBXTSEncrypter(cipherFunc, key, tweakKey, tweak)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newXTSEncrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte, isGB bool) (_cipher.BlockMode, error) {
|
|
||||||
if len(tweak) != blockSize {
|
|
||||||
return nil, errors.New("cipher: invalid tweak length")
|
|
||||||
}
|
|
||||||
|
|
||||||
k1, err := cipherFunc(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if k1.BlockSize() != blockSize {
|
|
||||||
return nil, errors.New("cipher: cipher does not have a block size of 16")
|
|
||||||
}
|
|
||||||
|
|
||||||
k2, err := cipherFunc(tweakKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if xtsable, ok := k1.(xtsEncAble); ok {
|
|
||||||
var encryptedTweak [blockSize]byte
|
|
||||||
k2.Encrypt(encryptedTweak[:], tweak)
|
|
||||||
return xtsable.NewXTSEncrypter(&encryptedTweak, isGB), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
c := &xts{
|
|
||||||
b: k1,
|
|
||||||
isGB: isGB,
|
|
||||||
}
|
|
||||||
k2.Encrypt(c.tweak[:], tweak)
|
|
||||||
return (*xtsEncrypter)(c), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type xtsDecrypter xts
|
|
||||||
|
|
||||||
// xtsDecAble is an interface implemented by ciphers that have a specific
|
|
||||||
// optimized implementation of XTS encryption, like sm4.
|
|
||||||
// NewXTSDecrypter will check for this interface and return the specific
|
|
||||||
// BlockMode if found.
|
|
||||||
type xtsDecAble interface {
|
|
||||||
NewXTSDecrypter(encryptedTweak *[blockSize]byte, isGB bool) _cipher.BlockMode
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewXTSDecrypter creates a Cipher given a function for creating the underlying
|
// NewXTSDecrypter creates a Cipher given a function for creating the underlying
|
||||||
// block cipher (which must have a block size of 16 bytes) for decryption.
|
// block cipher (which must have a block size of 16 bytes) for decryption.
|
||||||
func NewXTSDecrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (_cipher.BlockMode, error) {
|
func NewXTSDecrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (cipher.BlockMode, error) {
|
||||||
return newXTSDecrypter(cipherFunc, key, tweakKey, tweak, false)
|
return xts.NewXTSDecrypter(cipherFunc, key, tweakKey, tweak, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewXTSDecrypterWithSector creates a Cipher given a function for creating the underlying
|
// NewXTSDecrypterWithSector creates a Cipher given a function for creating the underlying
|
||||||
// block cipher (which must have a block size of 16 bytes) with sector number for decryption.
|
// block cipher (which must have a block size of 16 bytes) with sector number for decryption.
|
||||||
func NewXTSDecrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (_cipher.BlockMode, error) {
|
func NewXTSDecrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (cipher.BlockMode, error) {
|
||||||
tweak := make([]byte, blockSize)
|
tweak := make([]byte, blockSize)
|
||||||
byteorder.LEPutUint64(tweak[:8], sectorNum)
|
byteorder.LEPutUint64(tweak[:8], sectorNum)
|
||||||
return NewXTSDecrypter(cipherFunc, key, tweakKey, tweak)
|
return NewXTSDecrypter(cipherFunc, key, tweakKey, tweak)
|
||||||
@ -129,225 +54,15 @@ func NewXTSDecrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, s
|
|||||||
// NewGBXTSDecrypter creates a Cipher given a function for creating the underlying
|
// NewGBXTSDecrypter creates a Cipher given a function for creating the underlying
|
||||||
// block cipher (which must have a block size of 16 bytes) for decryption.
|
// block cipher (which must have a block size of 16 bytes) for decryption.
|
||||||
// It follows GB/T 17964-2021.
|
// It follows GB/T 17964-2021.
|
||||||
func NewGBXTSDecrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (_cipher.BlockMode, error) {
|
func NewGBXTSDecrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (cipher.BlockMode, error) {
|
||||||
return newXTSDecrypter(cipherFunc, key, tweakKey, tweak, true)
|
return xts.NewXTSDecrypter(cipherFunc, key, tweakKey, tweak, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGBXTSDecrypterWithSector creates a Cipher given a function for creating the underlying
|
// NewGBXTSDecrypterWithSector creates a Cipher given a function for creating the underlying
|
||||||
// block cipher (which must have a block size of 16 bytes) with sector number for decryption.
|
// block cipher (which must have a block size of 16 bytes) with sector number for decryption.
|
||||||
// It follows GB/T 17964-2021.
|
// It follows GB/T 17964-2021.
|
||||||
func NewGBXTSDecrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (_cipher.BlockMode, error) {
|
func NewGBXTSDecrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (cipher.BlockMode, error) {
|
||||||
tweak := make([]byte, blockSize)
|
tweak := make([]byte, blockSize)
|
||||||
byteorder.LEPutUint64(tweak[:8], sectorNum)
|
byteorder.LEPutUint64(tweak[:8], sectorNum)
|
||||||
return NewGBXTSDecrypter(cipherFunc, key, tweakKey, tweak)
|
return NewGBXTSDecrypter(cipherFunc, key, tweakKey, tweak)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newXTSDecrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte, isGB bool) (_cipher.BlockMode, error) {
|
|
||||||
if len(tweak) != blockSize {
|
|
||||||
return nil, errors.New("cipher: invalid tweak length")
|
|
||||||
}
|
|
||||||
|
|
||||||
k1, err := cipherFunc(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if k1.BlockSize() != blockSize {
|
|
||||||
return nil, errors.New("cipher: cipher does not have a block size of 16")
|
|
||||||
}
|
|
||||||
|
|
||||||
k2, err := cipherFunc(tweakKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if xtsable, ok := k1.(xtsDecAble); ok {
|
|
||||||
var encryptedTweak [blockSize]byte
|
|
||||||
k2.Encrypt(encryptedTweak[:], tweak)
|
|
||||||
return xtsable.NewXTSDecrypter(&encryptedTweak, isGB), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
c := &xts{
|
|
||||||
b: k1,
|
|
||||||
isGB: isGB,
|
|
||||||
}
|
|
||||||
k2.Encrypt(c.tweak[:], tweak)
|
|
||||||
return (*xtsDecrypter)(c), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *xtsEncrypter) BlockSize() int {
|
|
||||||
return blockSize
|
|
||||||
}
|
|
||||||
|
|
||||||
// CryptBlocks encrypts a sector of plaintext and puts the result into ciphertext.
|
|
||||||
// Plaintext and ciphertext must overlap entirely or not at all.
|
|
||||||
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
|
|
||||||
func (c *xtsEncrypter) CryptBlocks(ciphertext, plaintext []byte) {
|
|
||||||
if len(ciphertext) < len(plaintext) {
|
|
||||||
panic("cipher: ciphertext is smaller than plaintext")
|
|
||||||
}
|
|
||||||
if len(plaintext) < blockSize {
|
|
||||||
panic("cipher: plaintext length is smaller than the block size")
|
|
||||||
}
|
|
||||||
if alias.InexactOverlap(ciphertext[:len(plaintext)], plaintext) {
|
|
||||||
panic("cipher: invalid buffer overlap")
|
|
||||||
}
|
|
||||||
|
|
||||||
lastCiphertext := ciphertext
|
|
||||||
|
|
||||||
if concCipher, ok := c.b.(concurrentBlocks); ok {
|
|
||||||
batchSize := concCipher.Concurrency() * blockSize
|
|
||||||
var tweaks []byte = make([]byte, batchSize)
|
|
||||||
for len(plaintext) >= batchSize {
|
|
||||||
doubleTweaks(&c.tweak, tweaks, c.isGB)
|
|
||||||
subtle.XORBytes(ciphertext, plaintext, tweaks)
|
|
||||||
concCipher.EncryptBlocks(ciphertext, ciphertext)
|
|
||||||
subtle.XORBytes(ciphertext, ciphertext, tweaks)
|
|
||||||
plaintext = plaintext[batchSize:]
|
|
||||||
lastCiphertext = ciphertext[batchSize-blockSize:]
|
|
||||||
ciphertext = ciphertext[batchSize:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for len(plaintext) >= blockSize {
|
|
||||||
subtle.XORBytes(ciphertext, plaintext, c.tweak[:])
|
|
||||||
c.b.Encrypt(ciphertext, ciphertext)
|
|
||||||
subtle.XORBytes(ciphertext, ciphertext, c.tweak[:])
|
|
||||||
plaintext = plaintext[blockSize:]
|
|
||||||
lastCiphertext = ciphertext
|
|
||||||
ciphertext = ciphertext[blockSize:]
|
|
||||||
mul2(&c.tweak, c.isGB)
|
|
||||||
}
|
|
||||||
// is there a final partial block to handle?
|
|
||||||
if remain := len(plaintext); remain > 0 {
|
|
||||||
var x [blockSize]byte
|
|
||||||
//Copy the final plaintext bytes
|
|
||||||
copy(x[:], plaintext)
|
|
||||||
//Steal ciphertext to complete the block
|
|
||||||
copy(x[remain:], lastCiphertext[remain:blockSize])
|
|
||||||
//Copy the final ciphertext bytes
|
|
||||||
copy(ciphertext, lastCiphertext[:remain])
|
|
||||||
//Merge the tweak into the input block
|
|
||||||
subtle.XORBytes(x[:], x[:], c.tweak[:])
|
|
||||||
//Encrypt the final block using K1
|
|
||||||
c.b.Encrypt(x[:], x[:])
|
|
||||||
//Merge the tweak into the output block
|
|
||||||
subtle.XORBytes(lastCiphertext, x[:], c.tweak[:])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *xtsDecrypter) BlockSize() int {
|
|
||||||
return blockSize
|
|
||||||
}
|
|
||||||
|
|
||||||
// CryptBlocks decrypts a sector of ciphertext and puts the result into plaintext.
|
|
||||||
// Plaintext and ciphertext must overlap entirely or not at all.
|
|
||||||
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
|
|
||||||
func (c *xtsDecrypter) CryptBlocks(plaintext, ciphertext []byte) {
|
|
||||||
if len(plaintext) < len(ciphertext) {
|
|
||||||
panic("cipher: plaintext is smaller than ciphertext")
|
|
||||||
}
|
|
||||||
if len(ciphertext) < blockSize {
|
|
||||||
panic("cipher: ciphertext length is smaller than the block size")
|
|
||||||
}
|
|
||||||
if alias.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) {
|
|
||||||
panic("cipher: invalid buffer overlap")
|
|
||||||
}
|
|
||||||
|
|
||||||
if concCipher, ok := c.b.(concurrentBlocks); ok {
|
|
||||||
batchSize := concCipher.Concurrency() * blockSize
|
|
||||||
var tweaks []byte = make([]byte, batchSize)
|
|
||||||
|
|
||||||
for len(ciphertext) >= batchSize {
|
|
||||||
doubleTweaks(&c.tweak, tweaks, c.isGB)
|
|
||||||
subtle.XORBytes(plaintext, ciphertext, tweaks)
|
|
||||||
concCipher.DecryptBlocks(plaintext, plaintext)
|
|
||||||
subtle.XORBytes(plaintext, plaintext, tweaks)
|
|
||||||
plaintext = plaintext[batchSize:]
|
|
||||||
ciphertext = ciphertext[batchSize:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for len(ciphertext) >= 2*blockSize {
|
|
||||||
subtle.XORBytes(plaintext, ciphertext, c.tweak[:])
|
|
||||||
c.b.Decrypt(plaintext, plaintext)
|
|
||||||
subtle.XORBytes(plaintext, plaintext, c.tweak[:])
|
|
||||||
plaintext = plaintext[blockSize:]
|
|
||||||
ciphertext = ciphertext[blockSize:]
|
|
||||||
|
|
||||||
mul2(&c.tweak, c.isGB)
|
|
||||||
}
|
|
||||||
|
|
||||||
if remain := len(ciphertext); remain >= blockSize {
|
|
||||||
var x [blockSize]byte
|
|
||||||
if remain > blockSize {
|
|
||||||
var tt [blockSize]byte
|
|
||||||
copy(tt[:], c.tweak[:])
|
|
||||||
mul2(&tt, c.isGB)
|
|
||||||
subtle.XORBytes(x[:], ciphertext, tt[:])
|
|
||||||
c.b.Decrypt(x[:], x[:])
|
|
||||||
subtle.XORBytes(plaintext, x[:], tt[:])
|
|
||||||
|
|
||||||
//Retrieve the length of the final block
|
|
||||||
remain -= blockSize
|
|
||||||
|
|
||||||
//Copy the final ciphertext bytes
|
|
||||||
copy(x[:], ciphertext[blockSize:])
|
|
||||||
//Steal ciphertext to complete the block
|
|
||||||
copy(x[remain:], plaintext[remain:blockSize])
|
|
||||||
//Copy the final plaintext bytes
|
|
||||||
copy(plaintext[blockSize:], plaintext)
|
|
||||||
|
|
||||||
subtle.XORBytes(x[:], x[:], c.tweak[:])
|
|
||||||
c.b.Decrypt(x[:], x[:])
|
|
||||||
subtle.XORBytes(plaintext, x[:], c.tweak[:])
|
|
||||||
} else {
|
|
||||||
//The last block contains exactly 128 bits
|
|
||||||
subtle.XORBytes(plaintext, ciphertext, c.tweak[:])
|
|
||||||
c.b.Decrypt(plaintext, plaintext)
|
|
||||||
subtle.XORBytes(plaintext, plaintext, c.tweak[:])
|
|
||||||
// Maybe there are still ciphertext
|
|
||||||
mul2(&c.tweak, c.isGB)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mul2Generic multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
|
|
||||||
// x¹²⁸ + x⁷ + x² + x + 1.
|
|
||||||
func mul2Generic(tweak *[blockSize]byte, isGB bool) {
|
|
||||||
var carryIn byte
|
|
||||||
if !isGB {
|
|
||||||
// the coefficient of x⁰ can be obtained by tweak[0] & 1
|
|
||||||
// the coefficient of x⁷ can be obtained by tweak[0] >> 7
|
|
||||||
// the coefficient of x¹²⁰ can be obtained by tweak[15] & 1
|
|
||||||
// the coefficient of x¹²⁷ can be obtained by tweak[15] >> 7
|
|
||||||
for j := range tweak {
|
|
||||||
carryOut := tweak[j] >> 7
|
|
||||||
tweak[j] = (tweak[j] << 1) + carryIn
|
|
||||||
carryIn = carryOut
|
|
||||||
}
|
|
||||||
if carryIn != 0 {
|
|
||||||
// If we have a carry bit then we need to subtract a multiple
|
|
||||||
// of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
|
|
||||||
// By dropping the carry bit, we're subtracting the x^128 term
|
|
||||||
// so all that remains is to subtract x⁷ + x² + x + 1.
|
|
||||||
// Subtraction (and addition) in this representation is just
|
|
||||||
// XOR.
|
|
||||||
tweak[0] ^= GF128_FDBK // 1<<7 | 1<<2 | 1<<1 | 1
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// GB/T 17964-2021,
|
|
||||||
// the coefficient of x⁰ can be obtained by tweak[0] >> 7
|
|
||||||
// the coefficient of x⁷ can be obtained by tweak[0] & 1
|
|
||||||
// the coefficient of x¹²⁰ can be obtained by tweak[15] >> 7
|
|
||||||
// the coefficient of x¹²⁷ can be obtained by tweak[15] & 1
|
|
||||||
for j := range tweak {
|
|
||||||
carryOut := (tweak[j] << 7) & 0x80
|
|
||||||
tweak[j] = (tweak[j] >> 1) + carryIn
|
|
||||||
carryIn = carryOut
|
|
||||||
}
|
|
||||||
if carryIn != 0 {
|
|
||||||
tweak[0] ^= 0xE1 // 1<<7 | 1<<6 | 1<<5 | 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -104,7 +104,8 @@ SADK 3.2之后的版本,支持下列SM2密文格式(encryptedType):
|
|||||||
* 0x02/0x03 - C1为压缩点格式,具体是C1C3C2还是C1C2C3取决于解密时的选项参数,默认为C1C3C2。
|
* 0x02/0x03 - C1为压缩点格式,具体是C1C3C2还是C1C2C3取决于解密时的选项参数,默认为C1C3C2。
|
||||||
|
|
||||||
### 生成双密钥CSR (v0.29.6+)
|
### 生成双密钥CSR (v0.29.6+)
|
||||||
`cfca.CreateCertificateRequest`,和CFCA SADK不同,调用者需要自行先生成两对密钥对,一对用于签名证书,一对用于加解密CFCA生成的加密用私钥文件(CFCA加密,申请者解密)。
|
`cfca.CreateCertificateRequest`,和CFCA SADK不同,调用者需要自行先生成两对密钥对,一对用于签名证书,一对用于加解密CFCA生成的加密用私钥文件(CFCA加密,申请者解密)。这个方法对应CFCA的`cfca.sadk.util.P10Request.generateDoublePKCS10Request`方法。按我的理解,非国密(RSA)应该不需要支持这种双密钥对机制,不过既然**CFCA SADK**支持,本软件库从**v0.30.0**开始也支持。
|
||||||
|
|
||||||
使用`cfca.ParseEscrowPrivateKey`解析CFCA返回的加密用私钥。
|
使用`cfca.ParseEscrowPrivateKey`解析CFCA返回的加密用私钥。
|
||||||
|
|
||||||
### SM2私钥、证书的解析
|
### SM2私钥、证书的解析
|
||||||
|
@ -99,6 +99,10 @@ func ExampleNewCipher_zuc256() {
|
|||||||
// Output: some plaintext
|
// Output: some plaintext
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
### Seekable Stream
|
||||||
|
完整性算法支持Seekable Stream,也就是随机定位到某点进行处理,内部实现了分桶缓存状态,每个状态的大小大概是88字节,`bucketSize`的大小可以结合要处理的流大小以及内存占用来平衡考虑。同时,`bucketSize`内部会被处理成128字节的倍数,以利于实现。
|
||||||
|
|
||||||
|
如果您没有对同一个流反复进行**前进**、**后退**加解密的需求,可以使用`NewCipher`或者`NewEEACipher`方法,避免内部状态缓存。
|
||||||
|
|
||||||
## 完整性算法
|
## 完整性算法
|
||||||
完整性算法实现了```hash.Hash```接口,所以其使用方法和其它哈希算法类似。
|
完整性算法实现了```hash.Hash```接口,所以其使用方法和其它哈希算法类似。
|
||||||
|
@ -2,11 +2,11 @@ package drbg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
"crypto/subtle"
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/internal/byteorder"
|
"github.com/emmansun/gmsm/internal/byteorder"
|
||||||
"github.com/emmansun/gmsm/internal/subtle"
|
|
||||||
"github.com/emmansun/gmsm/sm4"
|
"github.com/emmansun/gmsm/sm4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -120,12 +120,12 @@ func (hd *CtrDrbg) MaxBytesPerRequest() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate CTR DRBG pseudorandom bits generate process.
|
// Generate CTR DRBG pseudorandom bits generate process.
|
||||||
func (hd *CtrDrbg) Generate(b, additional []byte) error {
|
func (hd *CtrDrbg) Generate(out, additional []byte) error {
|
||||||
if hd.NeedReseed() {
|
if hd.NeedReseed() {
|
||||||
return ErrReseedRequired
|
return ErrReseedRequired
|
||||||
}
|
}
|
||||||
outlen := len(hd.v)
|
outlen := len(hd.v)
|
||||||
if (hd.gm && len(b) > outlen) || (!hd.gm && len(b) > MAX_BYTES_PER_GENERATE) {
|
if (hd.gm && len(out) > outlen) || (!hd.gm && len(out) > MAX_BYTES_PER_GENERATE) {
|
||||||
return errors.New("drbg: too many bytes requested")
|
return errors.New("drbg: too many bytes requested")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,14 +140,14 @@ func (hd *CtrDrbg) Generate(b, additional []byte) error {
|
|||||||
block := hd.newBlockCipher(hd.key)
|
block := hd.newBlockCipher(hd.key)
|
||||||
temp := make([]byte, outlen)
|
temp := make([]byte, outlen)
|
||||||
|
|
||||||
m := len(b)
|
m := len(out)
|
||||||
limit := uint64(m+outlen-1) / uint64(outlen)
|
limit := uint64(m+outlen-1) / uint64(outlen)
|
||||||
for i := 0; i < int(limit); i++ {
|
for i := range int(limit) {
|
||||||
// V = (V + 1) mod 2^outlen)
|
// V = (V + 1) mod 2^outlen)
|
||||||
addOne(hd.v, outlen)
|
addOne(hd.v, outlen)
|
||||||
// output_block = Encrypt(Key, V)
|
// output_block = Encrypt(Key, V)
|
||||||
block.Encrypt(temp, hd.v)
|
block.Encrypt(temp, hd.v)
|
||||||
copy(b[i*outlen:], temp)
|
copy(out[i*outlen:], temp)
|
||||||
}
|
}
|
||||||
hd.update(additional)
|
hd.update(additional)
|
||||||
hd.reseedCounter++
|
hd.reseedCounter++
|
||||||
@ -162,7 +162,7 @@ func (cd *CtrDrbg) update(seedMaterial []byte) {
|
|||||||
v := make([]byte, outlen)
|
v := make([]byte, outlen)
|
||||||
output := make([]byte, outlen)
|
output := make([]byte, outlen)
|
||||||
copy(v, cd.v)
|
copy(v, cd.v)
|
||||||
for i := 0; i < (cd.seedLength+outlen-1)/outlen; i++ {
|
for i := range (cd.seedLength+outlen-1)/outlen {
|
||||||
// V = (V + 1) mod 2^outlen
|
// V = (V + 1) mod 2^outlen
|
||||||
addOne(v, outlen)
|
addOne(v, outlen)
|
||||||
// output_block = Encrypt(Key, V)
|
// output_block = Encrypt(Key, V)
|
||||||
@ -191,7 +191,7 @@ func (cd *CtrDrbg) derive(seedMaterial []byte, returnBytes int) []byte {
|
|||||||
S[outlen+8+len(seedMaterial)] = 0x80
|
S[outlen+8+len(seedMaterial)] = 0x80
|
||||||
|
|
||||||
key := make([]byte, cd.keyLen)
|
key := make([]byte, cd.keyLen)
|
||||||
for i := 0; i < cd.keyLen; i++ {
|
for i := range cd.keyLen {
|
||||||
key[i] = byte(i)
|
key[i] = byte(i)
|
||||||
}
|
}
|
||||||
blocks := (cd.seedLength + outlen - 1) / outlen
|
blocks := (cd.seedLength + outlen - 1) / outlen
|
||||||
|
@ -187,7 +187,7 @@ func (hd *HashDrbg) Generate(b, additional []byte) error {
|
|||||||
limit := uint64(m+md.Size()-1) / uint64(md.Size())
|
limit := uint64(m+md.Size()-1) / uint64(md.Size())
|
||||||
data := make([]byte, hd.seedLength)
|
data := make([]byte, hd.seedLength)
|
||||||
copy(data, hd.v)
|
copy(data, hd.v)
|
||||||
for i := 0; i < int(limit); i++ {
|
for i := range int(limit) {
|
||||||
md.Write(data)
|
md.Write(data)
|
||||||
copy(b[i*md.Size():], md.Sum(nil))
|
copy(b[i*md.Size():], md.Sum(nil))
|
||||||
addOne(data, hd.seedLength)
|
addOne(data, hd.seedLength)
|
||||||
@ -211,7 +211,7 @@ func (hd *HashDrbg) derive(seedMaterial []byte, len int) []byte {
|
|||||||
byteorder.BEPutUint32(requireBytes[:], uint32(len<<3))
|
byteorder.BEPutUint32(requireBytes[:], uint32(len<<3))
|
||||||
var ct byte = 1
|
var ct byte = 1
|
||||||
k := make([]byte, len)
|
k := make([]byte, len)
|
||||||
for i := 0; i < int(limit); i++ {
|
for i := range int(limit) {
|
||||||
// Hash( counter_byte || return_bits || seed_material )
|
// Hash( counter_byte || return_bits || seed_material )
|
||||||
md.Write([]byte{ct})
|
md.Write([]byte{ct})
|
||||||
md.Write(requireBytes[:])
|
md.Write(requireBytes[:])
|
||||||
|
@ -45,7 +45,7 @@ func NewHmacDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, gm bool,
|
|||||||
// HMAC_DRBG_Instantiate_process
|
// HMAC_DRBG_Instantiate_process
|
||||||
hd.key = make([]byte, hd.hashSize)
|
hd.key = make([]byte, hd.hashSize)
|
||||||
hd.v = make([]byte, hd.hashSize)
|
hd.v = make([]byte, hd.hashSize)
|
||||||
for i := 0; i < hd.hashSize; i++ {
|
for i := range hd.hashSize {
|
||||||
hd.key[i] = 0x00
|
hd.key[i] = 0x00
|
||||||
hd.v[i] = 0x01
|
hd.v[i] = 0x01
|
||||||
}
|
}
|
||||||
|
@ -374,9 +374,7 @@ type zr struct{}
|
|||||||
|
|
||||||
// Read replaces the contents of dst with zeros. It is safe for concurrent use.
|
// Read replaces the contents of dst with zeros. It is safe for concurrent use.
|
||||||
func (zr) Read(dst []byte) (n int, err error) {
|
func (zr) Read(dst []byte) (n int, err error) {
|
||||||
for i := range dst {
|
clear(dst)
|
||||||
dst[i] = 0
|
|
||||||
}
|
|
||||||
return len(dst), nil
|
return len(dst), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
go.mod
9
go.mod
@ -1,8 +1,7 @@
|
|||||||
module github.com/emmansun/gmsm
|
module github.com/emmansun/gmsm
|
||||||
|
|
||||||
go 1.18
|
go 1.23.0
|
||||||
|
|
||||||
require (
|
require golang.org/x/crypto v0.37.0
|
||||||
golang.org/x/crypto v0.33.0
|
|
||||||
golang.org/x/sys v0.30.0
|
require golang.org/x/sys v0.32.0 // indirect
|
||||||
)
|
|
||||||
|
8
go.sum
8
go.sum
@ -1,4 +1,4 @@
|
|||||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
@ -85,10 +85,7 @@ func (x *Nat) expand(n int) *Nat {
|
|||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
extraLimbs := x.limbs[len(x.limbs):n]
|
extraLimbs := x.limbs[len(x.limbs):n]
|
||||||
// clear(extraLimbs)
|
clear(extraLimbs)
|
||||||
for i := range extraLimbs {
|
|
||||||
extraLimbs[i] = 0
|
|
||||||
}
|
|
||||||
x.limbs = x.limbs[:n]
|
x.limbs = x.limbs[:n]
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
@ -99,10 +96,8 @@ func (x *Nat) reset(n int) *Nat {
|
|||||||
x.limbs = make([]uint, n)
|
x.limbs = make([]uint, n)
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
// clear(x.limbs)
|
// Clear both the returned limbs and the previously used ones.
|
||||||
for i := range x.limbs {
|
clear(x.limbs[:max(n, len(x.limbs))])
|
||||||
x.limbs[i] = 0
|
|
||||||
}
|
|
||||||
x.limbs = x.limbs[:n]
|
x.limbs = x.limbs[:n]
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
package bigmod
|
package bigmod
|
||||||
|
|
||||||
import "golang.org/x/sys/cpu"
|
import "github.com/emmansun/gmsm/internal/deps/cpu"
|
||||||
|
|
||||||
// amd64 assembly uses ADCX/ADOX/MULX if ADX is available to run two carry
|
// amd64 assembly uses ADCX/ADOX/MULX if ADX is available to run two carry
|
||||||
// chains in the flags in parallel across the whole operation, and aggressively
|
// chains in the flags in parallel across the whole operation, and aggressively
|
||||||
|
292
internal/cipher/xts/xts.go
Normal file
292
internal/cipher/xts/xts.go
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
// Package xts implements XTS encryption mode, as specified in IEEE P1619/D16 and GB/T 17964-2021.
|
||||||
|
package xts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/subtle"
|
||||||
|
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/emmansun/gmsm/internal/alias"
|
||||||
|
)
|
||||||
|
|
||||||
|
const GF128_FDBK byte = 0x87
|
||||||
|
|
||||||
|
type concurrentBlocks interface {
|
||||||
|
Concurrency() int
|
||||||
|
EncryptBlocks(dst, src []byte)
|
||||||
|
DecryptBlocks(dst, src []byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cipher contains an expanded key structure. It is unsafe for concurrent use.
|
||||||
|
type xts struct {
|
||||||
|
b cipher.Block
|
||||||
|
tweak [blockSize]byte
|
||||||
|
isGB bool // if true, follows GB/T 17964-2021
|
||||||
|
}
|
||||||
|
|
||||||
|
// blockSize is the block size that the underlying cipher must have. XTS is
|
||||||
|
// only defined for 16-byte ciphers.
|
||||||
|
const blockSize = 16
|
||||||
|
|
||||||
|
type xtsEncrypter xts
|
||||||
|
|
||||||
|
// xtsEncAble is an interface implemented by ciphers that have a specific
|
||||||
|
// optimized implementation of XTS encryption, like sm4.
|
||||||
|
// NewXTSEncrypter will check for this interface and return the specific
|
||||||
|
// BlockMode if found.
|
||||||
|
type xtsEncAble interface {
|
||||||
|
NewXTSEncrypter(encryptedTweak *[blockSize]byte, isGB bool) cipher.BlockMode
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewXTSEncrypter(cipherFunc func([]byte) (cipher.Block, error), key, tweakKey, tweak []byte, isGB bool) (cipher.BlockMode, error) {
|
||||||
|
if len(tweak) != blockSize {
|
||||||
|
return nil, errors.New("cipher: invalid tweak length")
|
||||||
|
}
|
||||||
|
|
||||||
|
k1, err := cipherFunc(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if k1.BlockSize() != blockSize {
|
||||||
|
return nil, errors.New("cipher: cipher does not have a block size of 16")
|
||||||
|
}
|
||||||
|
|
||||||
|
k2, err := cipherFunc(tweakKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if xtsable, ok := k1.(xtsEncAble); ok {
|
||||||
|
var encryptedTweak [blockSize]byte
|
||||||
|
k2.Encrypt(encryptedTweak[:], tweak)
|
||||||
|
return xtsable.NewXTSEncrypter(&encryptedTweak, isGB), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &xts{
|
||||||
|
b: k1,
|
||||||
|
isGB: isGB,
|
||||||
|
}
|
||||||
|
k2.Encrypt(c.tweak[:], tweak)
|
||||||
|
return (*xtsEncrypter)(c), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type xtsDecrypter xts
|
||||||
|
|
||||||
|
// xtsDecAble is an interface implemented by ciphers that have a specific
|
||||||
|
// optimized implementation of XTS encryption, like sm4.
|
||||||
|
// NewXTSDecrypter will check for this interface and return the specific
|
||||||
|
// BlockMode if found.
|
||||||
|
type xtsDecAble interface {
|
||||||
|
NewXTSDecrypter(encryptedTweak *[blockSize]byte, isGB bool) cipher.BlockMode
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewXTSDecrypter(cipherFunc func([]byte) (cipher.Block, error), key, tweakKey, tweak []byte, isGB bool) (cipher.BlockMode, error) {
|
||||||
|
if len(tweak) != blockSize {
|
||||||
|
return nil, errors.New("cipher: invalid tweak length")
|
||||||
|
}
|
||||||
|
|
||||||
|
k1, err := cipherFunc(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if k1.BlockSize() != blockSize {
|
||||||
|
return nil, errors.New("cipher: cipher does not have a block size of 16")
|
||||||
|
}
|
||||||
|
|
||||||
|
k2, err := cipherFunc(tweakKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if xtsable, ok := k1.(xtsDecAble); ok {
|
||||||
|
var encryptedTweak [blockSize]byte
|
||||||
|
k2.Encrypt(encryptedTweak[:], tweak)
|
||||||
|
return xtsable.NewXTSDecrypter(&encryptedTweak, isGB), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &xts{
|
||||||
|
b: k1,
|
||||||
|
isGB: isGB,
|
||||||
|
}
|
||||||
|
k2.Encrypt(c.tweak[:], tweak)
|
||||||
|
return (*xtsDecrypter)(c), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *xtsEncrypter) BlockSize() int {
|
||||||
|
return blockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptBlocks encrypts a sector of plaintext and puts the result into ciphertext.
|
||||||
|
// Plaintext and ciphertext must overlap entirely or not at all.
|
||||||
|
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
|
||||||
|
func (c *xtsEncrypter) CryptBlocks(ciphertext, plaintext []byte) {
|
||||||
|
if len(ciphertext) < len(plaintext) {
|
||||||
|
panic("cipher: ciphertext is smaller than plaintext")
|
||||||
|
}
|
||||||
|
if len(plaintext) < blockSize {
|
||||||
|
panic("cipher: plaintext length is smaller than the block size")
|
||||||
|
}
|
||||||
|
if alias.InexactOverlap(ciphertext[:len(plaintext)], plaintext) {
|
||||||
|
panic("cipher: invalid buffer overlap")
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCiphertext := ciphertext
|
||||||
|
|
||||||
|
if concCipher, ok := c.b.(concurrentBlocks); ok {
|
||||||
|
batchSize := concCipher.Concurrency() * blockSize
|
||||||
|
var tweaks []byte = make([]byte, batchSize)
|
||||||
|
for len(plaintext) >= batchSize {
|
||||||
|
doubleTweaks(&c.tweak, tweaks, c.isGB)
|
||||||
|
subtle.XORBytes(ciphertext, plaintext, tweaks)
|
||||||
|
concCipher.EncryptBlocks(ciphertext, ciphertext)
|
||||||
|
subtle.XORBytes(ciphertext, ciphertext, tweaks)
|
||||||
|
plaintext = plaintext[batchSize:]
|
||||||
|
lastCiphertext = ciphertext[batchSize-blockSize:]
|
||||||
|
ciphertext = ciphertext[batchSize:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(plaintext) >= blockSize {
|
||||||
|
subtle.XORBytes(ciphertext, plaintext, c.tweak[:])
|
||||||
|
c.b.Encrypt(ciphertext, ciphertext)
|
||||||
|
subtle.XORBytes(ciphertext, ciphertext, c.tweak[:])
|
||||||
|
plaintext = plaintext[blockSize:]
|
||||||
|
lastCiphertext = ciphertext
|
||||||
|
ciphertext = ciphertext[blockSize:]
|
||||||
|
mul2(&c.tweak, c.isGB)
|
||||||
|
}
|
||||||
|
// is there a final partial block to handle?
|
||||||
|
if remain := len(plaintext); remain > 0 {
|
||||||
|
var x [blockSize]byte
|
||||||
|
//Copy the final plaintext bytes
|
||||||
|
copy(x[:], plaintext)
|
||||||
|
//Steal ciphertext to complete the block
|
||||||
|
copy(x[remain:], lastCiphertext[remain:blockSize])
|
||||||
|
//Copy the final ciphertext bytes
|
||||||
|
copy(ciphertext, lastCiphertext[:remain])
|
||||||
|
//Merge the tweak into the input block
|
||||||
|
subtle.XORBytes(x[:], x[:], c.tweak[:])
|
||||||
|
//Encrypt the final block using K1
|
||||||
|
c.b.Encrypt(x[:], x[:])
|
||||||
|
//Merge the tweak into the output block
|
||||||
|
subtle.XORBytes(lastCiphertext, x[:], c.tweak[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *xtsDecrypter) BlockSize() int {
|
||||||
|
return blockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptBlocks decrypts a sector of ciphertext and puts the result into plaintext.
|
||||||
|
// Plaintext and ciphertext must overlap entirely or not at all.
|
||||||
|
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
|
||||||
|
func (c *xtsDecrypter) CryptBlocks(plaintext, ciphertext []byte) {
|
||||||
|
if len(plaintext) < len(ciphertext) {
|
||||||
|
panic("cipher: plaintext is smaller than ciphertext")
|
||||||
|
}
|
||||||
|
if len(ciphertext) < blockSize {
|
||||||
|
panic("cipher: ciphertext length is smaller than the block size")
|
||||||
|
}
|
||||||
|
if alias.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) {
|
||||||
|
panic("cipher: invalid buffer overlap")
|
||||||
|
}
|
||||||
|
|
||||||
|
if concCipher, ok := c.b.(concurrentBlocks); ok {
|
||||||
|
batchSize := concCipher.Concurrency() * blockSize
|
||||||
|
var tweaks []byte = make([]byte, batchSize)
|
||||||
|
|
||||||
|
for len(ciphertext) >= batchSize {
|
||||||
|
doubleTweaks(&c.tweak, tweaks, c.isGB)
|
||||||
|
subtle.XORBytes(plaintext, ciphertext, tweaks)
|
||||||
|
concCipher.DecryptBlocks(plaintext, plaintext)
|
||||||
|
subtle.XORBytes(plaintext, plaintext, tweaks)
|
||||||
|
plaintext = plaintext[batchSize:]
|
||||||
|
ciphertext = ciphertext[batchSize:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(ciphertext) >= 2*blockSize {
|
||||||
|
subtle.XORBytes(plaintext, ciphertext, c.tweak[:])
|
||||||
|
c.b.Decrypt(plaintext, plaintext)
|
||||||
|
subtle.XORBytes(plaintext, plaintext, c.tweak[:])
|
||||||
|
plaintext = plaintext[blockSize:]
|
||||||
|
ciphertext = ciphertext[blockSize:]
|
||||||
|
|
||||||
|
mul2(&c.tweak, c.isGB)
|
||||||
|
}
|
||||||
|
|
||||||
|
if remain := len(ciphertext); remain >= blockSize {
|
||||||
|
var x [blockSize]byte
|
||||||
|
if remain > blockSize {
|
||||||
|
var tt [blockSize]byte
|
||||||
|
copy(tt[:], c.tweak[:])
|
||||||
|
mul2(&tt, c.isGB)
|
||||||
|
subtle.XORBytes(x[:], ciphertext, tt[:])
|
||||||
|
c.b.Decrypt(x[:], x[:])
|
||||||
|
subtle.XORBytes(plaintext, x[:], tt[:])
|
||||||
|
|
||||||
|
//Retrieve the length of the final block
|
||||||
|
remain -= blockSize
|
||||||
|
|
||||||
|
//Copy the final ciphertext bytes
|
||||||
|
copy(x[:], ciphertext[blockSize:])
|
||||||
|
//Steal ciphertext to complete the block
|
||||||
|
copy(x[remain:], plaintext[remain:blockSize])
|
||||||
|
//Copy the final plaintext bytes
|
||||||
|
copy(plaintext[blockSize:], plaintext)
|
||||||
|
|
||||||
|
subtle.XORBytes(x[:], x[:], c.tweak[:])
|
||||||
|
c.b.Decrypt(x[:], x[:])
|
||||||
|
subtle.XORBytes(plaintext, x[:], c.tweak[:])
|
||||||
|
} else {
|
||||||
|
//The last block contains exactly 128 bits
|
||||||
|
subtle.XORBytes(plaintext, ciphertext, c.tweak[:])
|
||||||
|
c.b.Decrypt(plaintext, plaintext)
|
||||||
|
subtle.XORBytes(plaintext, plaintext, c.tweak[:])
|
||||||
|
// Maybe there are still ciphertext
|
||||||
|
mul2(&c.tweak, c.isGB)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mul2Generic multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
|
||||||
|
// x¹²⁸ + x⁷ + x² + x + 1.
|
||||||
|
func mul2Generic(tweak *[blockSize]byte, isGB bool) {
|
||||||
|
var carryIn byte
|
||||||
|
if !isGB {
|
||||||
|
// the coefficient of x⁰ can be obtained by tweak[0] & 1
|
||||||
|
// the coefficient of x⁷ can be obtained by tweak[0] >> 7
|
||||||
|
// the coefficient of x¹²⁰ can be obtained by tweak[15] & 1
|
||||||
|
// the coefficient of x¹²⁷ can be obtained by tweak[15] >> 7
|
||||||
|
for j := range tweak {
|
||||||
|
carryOut := tweak[j] >> 7
|
||||||
|
tweak[j] = (tweak[j] << 1) + carryIn
|
||||||
|
carryIn = carryOut
|
||||||
|
}
|
||||||
|
if carryIn != 0 {
|
||||||
|
// If we have a carry bit then we need to subtract a multiple
|
||||||
|
// of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
|
||||||
|
// By dropping the carry bit, we're subtracting the x^128 term
|
||||||
|
// so all that remains is to subtract x⁷ + x² + x + 1.
|
||||||
|
// Subtraction (and addition) in this representation is just
|
||||||
|
// XOR.
|
||||||
|
tweak[0] ^= GF128_FDBK // 1<<7 | 1<<2 | 1<<1 | 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// GB/T 17964-2021,
|
||||||
|
// the coefficient of x⁰ can be obtained by tweak[0] >> 7
|
||||||
|
// the coefficient of x⁷ can be obtained by tweak[0] & 1
|
||||||
|
// the coefficient of x¹²⁰ can be obtained by tweak[15] >> 7
|
||||||
|
// the coefficient of x¹²⁷ can be obtained by tweak[15] & 1
|
||||||
|
for j := range tweak {
|
||||||
|
carryOut := (tweak[j] << 7) & 0x80
|
||||||
|
tweak[j] = (tweak[j] >> 1) + carryIn
|
||||||
|
carryIn = carryOut
|
||||||
|
}
|
||||||
|
if carryIn != 0 {
|
||||||
|
tweak[0] ^= 0xE1 // 1<<7 | 1<<6 | 1<<5 | 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
//go:build (amd64 || arm64 || s390x || ppc64 || ppc64le) && !purego
|
//go:build (amd64 || arm64 || s390x || ppc64 || ppc64le) && !purego
|
||||||
|
|
||||||
package cipher
|
package xts
|
||||||
|
|
||||||
//go:noescape
|
//go:noescape
|
||||||
func mul2(tweak *[blockSize]byte, isGB bool)
|
func mul2(tweak *[blockSize]byte, isGB bool)
|
@ -1,6 +1,6 @@
|
|||||||
//go:build (amd64 || arm64 || s390x || ppc64 || ppc64le) && !purego
|
//go:build (amd64 || arm64 || s390x || ppc64 || ppc64le) && !purego
|
||||||
|
|
||||||
package cipher
|
package xts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
@ -1,6 +1,6 @@
|
|||||||
//go:build purego || !(amd64 || arm64 || s390x || ppc64 || ppc64le)
|
//go:build purego || !(amd64 || arm64 || s390x || ppc64 || ppc64le)
|
||||||
|
|
||||||
package cipher
|
package xts
|
||||||
|
|
||||||
func mul2(tweak *[blockSize]byte, isGB bool) {
|
func mul2(tweak *[blockSize]byte, isGB bool) {
|
||||||
mul2Generic(tweak, isGB)
|
mul2Generic(tweak, isGB)
|
||||||
@ -8,7 +8,7 @@ func mul2(tweak *[blockSize]byte, isGB bool) {
|
|||||||
|
|
||||||
func doubleTweaks(tweak *[blockSize]byte, tweaks []byte, isGB bool) {
|
func doubleTweaks(tweak *[blockSize]byte, tweaks []byte, isGB bool) {
|
||||||
count := len(tweaks) >> 4
|
count := len(tweaks) >> 4
|
||||||
for i := 0; i < count; i++ {
|
for i := range count {
|
||||||
copy(tweaks[blockSize*i:], tweak[:])
|
copy(tweaks[blockSize*i:], tweak[:])
|
||||||
mul2(tweak, isGB)
|
mul2(tweak, isGB)
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package cipher
|
package xts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/aes"
|
"crypto/aes"
|
@ -1,6 +1,6 @@
|
|||||||
package cpuid
|
package cpuid
|
||||||
|
|
||||||
import "golang.org/x/sys/cpu"
|
import "github.com/emmansun/gmsm/internal/deps/cpu"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
HasAES = cpu.X86.HasAES
|
HasAES = cpu.X86.HasAES
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
package cpuid
|
package cpuid
|
||||||
|
|
||||||
import "golang.org/x/sys/cpu"
|
import "github.com/emmansun/gmsm/internal/deps/cpu"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
HasAES = cpu.ARM64.HasAES
|
HasAES = cpu.ARM64.HasAES
|
||||||
|
@ -7,11 +7,10 @@ package cryptotest
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
"crypto/subtle"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/internal/subtle"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Each test is executed with each of the buffer lengths in bufLens.
|
// Each test is executed with each of the buffer lengths in bufLens.
|
||||||
|
17
internal/deps/cpu/asm_aix_ppc64.s
Normal file
17
internal/deps/cpu/asm_aix_ppc64.s
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build gc
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
|
||||||
|
//
|
||||||
|
|
||||||
|
TEXT ·syscall6(SB),NOSPLIT,$0-88
|
||||||
|
JMP syscall·syscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
|
||||||
|
JMP syscall·rawSyscall6(SB)
|
17
internal/deps/cpu/asm_arwin_x86_gc.s
Normal file
17
internal/deps/cpu/asm_arwin_x86_gc.s
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2024 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build darwin && amd64 && gc
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0
|
||||||
|
JMP libc_sysctl(SB)
|
||||||
|
GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8
|
||||||
|
DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB)
|
||||||
|
|
||||||
|
TEXT libc_sysctlbyname_trampoline<>(SB),NOSPLIT,$0-0
|
||||||
|
JMP libc_sysctlbyname(SB)
|
||||||
|
GLOBL ·libc_sysctlbyname_trampoline_addr(SB), RODATA, $8
|
||||||
|
DATA ·libc_sysctlbyname_trampoline_addr(SB)/8, $libc_sysctlbyname_trampoline<>(SB)
|
66
internal/deps/cpu/byteorder.go
Normal file
66
internal/deps/cpu/byteorder.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// byteOrder is a subset of encoding/binary.ByteOrder.
|
||||||
|
type byteOrder interface {
|
||||||
|
Uint32([]byte) uint32
|
||||||
|
Uint64([]byte) uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type littleEndian struct{}
|
||||||
|
type bigEndian struct{}
|
||||||
|
|
||||||
|
func (littleEndian) Uint32(b []byte) uint32 {
|
||||||
|
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
|
||||||
|
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||||
|
}
|
||||||
|
|
||||||
|
func (littleEndian) Uint64(b []byte) uint64 {
|
||||||
|
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||||
|
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
|
||||||
|
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bigEndian) Uint32(b []byte) uint32 {
|
||||||
|
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
|
||||||
|
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bigEndian) Uint64(b []byte) uint64 {
|
||||||
|
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||||
|
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
|
||||||
|
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
|
||||||
|
}
|
||||||
|
|
||||||
|
// hostByteOrder returns littleEndian on little-endian machines and
|
||||||
|
// bigEndian on big-endian machines.
|
||||||
|
func hostByteOrder() byteOrder {
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "386", "amd64", "amd64p32",
|
||||||
|
"alpha",
|
||||||
|
"arm", "arm64",
|
||||||
|
"loong64",
|
||||||
|
"mipsle", "mips64le", "mips64p32le",
|
||||||
|
"nios2",
|
||||||
|
"ppc64le",
|
||||||
|
"riscv", "riscv64",
|
||||||
|
"sh":
|
||||||
|
return littleEndian{}
|
||||||
|
case "armbe", "arm64be",
|
||||||
|
"m68k",
|
||||||
|
"mips", "mips64", "mips64p32",
|
||||||
|
"ppc", "ppc64",
|
||||||
|
"s390", "s390x",
|
||||||
|
"shbe",
|
||||||
|
"sparc", "sparc64":
|
||||||
|
return bigEndian{}
|
||||||
|
}
|
||||||
|
panic("unknown architecture")
|
||||||
|
}
|
315
internal/deps/cpu/cpu.go
Normal file
315
internal/deps/cpu/cpu.go
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package cpu implements processor feature detection for
|
||||||
|
// various CPU architectures.
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Initialized reports whether the CPU features were initialized.
|
||||||
|
//
|
||||||
|
// For some GOOS/GOARCH combinations initialization of the CPU features depends
|
||||||
|
// on reading an operating specific file, e.g. /proc/self/auxv on linux/arm
|
||||||
|
// Initialized will report false if reading the file fails.
|
||||||
|
var Initialized bool
|
||||||
|
|
||||||
|
// CacheLinePad is used to pad structs to avoid false sharing.
|
||||||
|
type CacheLinePad struct{ _ [cacheLineSize]byte }
|
||||||
|
|
||||||
|
// X86 contains the supported CPU features of the
|
||||||
|
// current X86/AMD64 platform. If the current platform
|
||||||
|
// is not X86/AMD64 then all feature flags are false.
|
||||||
|
//
|
||||||
|
// X86 is padded to avoid false sharing. Further the HasAVX
|
||||||
|
// and HasAVX2 are only set if the OS supports XMM and YMM
|
||||||
|
// registers in addition to the CPUID feature bit being set.
|
||||||
|
var X86 struct {
|
||||||
|
_ CacheLinePad
|
||||||
|
HasAES bool // AES hardware implementation (AES NI)
|
||||||
|
HasADX bool // Multi-precision add-carry instruction extensions
|
||||||
|
HasAVX bool // Advanced vector extension
|
||||||
|
HasAVX2 bool // Advanced vector extension 2
|
||||||
|
HasAVX512 bool // Advanced vector extension 512
|
||||||
|
HasAVX512F bool // Advanced vector extension 512 Foundation Instructions
|
||||||
|
HasAVX512CD bool // Advanced vector extension 512 Conflict Detection Instructions
|
||||||
|
HasAVX512ER bool // Advanced vector extension 512 Exponential and Reciprocal Instructions
|
||||||
|
HasAVX512PF bool // Advanced vector extension 512 Prefetch Instructions
|
||||||
|
HasAVX512VL bool // Advanced vector extension 512 Vector Length Extensions
|
||||||
|
HasAVX512BW bool // Advanced vector extension 512 Byte and Word Instructions
|
||||||
|
HasAVX512DQ bool // Advanced vector extension 512 Doubleword and Quadword Instructions
|
||||||
|
HasAVX512IFMA bool // Advanced vector extension 512 Integer Fused Multiply Add
|
||||||
|
HasAVX512VBMI bool // Advanced vector extension 512 Vector Byte Manipulation Instructions
|
||||||
|
HasAVX5124VNNIW bool // Advanced vector extension 512 Vector Neural Network Instructions Word variable precision
|
||||||
|
HasAVX5124FMAPS bool // Advanced vector extension 512 Fused Multiply Accumulation Packed Single precision
|
||||||
|
HasAVX512VPOPCNTDQ bool // Advanced vector extension 512 Double and quad word population count instructions
|
||||||
|
HasAVX512VPCLMULQDQ bool // Advanced vector extension 512 Vector carry-less multiply operations
|
||||||
|
HasAVX512VNNI bool // Advanced vector extension 512 Vector Neural Network Instructions
|
||||||
|
HasAVX512GFNI bool // Advanced vector extension 512 Galois field New Instructions
|
||||||
|
HasAVX512VAES bool // Advanced vector extension 512 Vector AES instructions
|
||||||
|
HasAVX512VBMI2 bool // Advanced vector extension 512 Vector Byte Manipulation Instructions 2
|
||||||
|
HasAVX512BITALG bool // Advanced vector extension 512 Bit Algorithms
|
||||||
|
HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions
|
||||||
|
HasAMXTile bool // Advanced Matrix Extension Tile instructions
|
||||||
|
HasAMXInt8 bool // Advanced Matrix Extension Int8 instructions
|
||||||
|
HasAMXBF16 bool // Advanced Matrix Extension BFloat16 instructions
|
||||||
|
HasBMI1 bool // Bit manipulation instruction set 1
|
||||||
|
HasBMI2 bool // Bit manipulation instruction set 2
|
||||||
|
HasCX16 bool // Compare and exchange 16 Bytes
|
||||||
|
HasERMS bool // Enhanced REP for MOVSB and STOSB
|
||||||
|
HasFMA bool // Fused-multiply-add instructions
|
||||||
|
HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
|
||||||
|
HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM
|
||||||
|
HasPOPCNT bool // Hamming weight instruction POPCNT.
|
||||||
|
HasRDRAND bool // RDRAND instruction (on-chip random number generator)
|
||||||
|
HasRDSEED bool // RDSEED instruction (on-chip random number generator)
|
||||||
|
HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64)
|
||||||
|
HasSSE3 bool // Streaming SIMD extension 3
|
||||||
|
HasSSSE3 bool // Supplemental streaming SIMD extension 3
|
||||||
|
HasSSE41 bool // Streaming SIMD extension 4 and 4.1
|
||||||
|
HasSSE42 bool // Streaming SIMD extension 4 and 4.2
|
||||||
|
HasAVXIFMA bool // Advanced vector extension Integer Fused Multiply Add
|
||||||
|
HasAVXVNNI bool // Advanced vector extension Vector Neural Network Instructions
|
||||||
|
HasAVXVNNIInt8 bool // Advanced vector extension Vector Neural Network Int8 instructions
|
||||||
|
_ CacheLinePad
|
||||||
|
}
|
||||||
|
|
||||||
|
// ARM64 contains the supported CPU features of the
|
||||||
|
// current ARMv8(aarch64) platform. If the current platform
|
||||||
|
// is not arm64 then all feature flags are false.
|
||||||
|
var ARM64 struct {
|
||||||
|
_ CacheLinePad
|
||||||
|
HasFP bool // Floating-point instruction set (always available)
|
||||||
|
HasASIMD bool // Advanced SIMD (always available)
|
||||||
|
HasEVTSTRM bool // Event stream support
|
||||||
|
HasAES bool // AES hardware implementation
|
||||||
|
HasPMULL bool // Polynomial multiplication instruction set
|
||||||
|
HasSHA1 bool // SHA1 hardware implementation
|
||||||
|
HasSHA2 bool // SHA2 hardware implementation
|
||||||
|
HasCRC32 bool // CRC32 hardware implementation
|
||||||
|
HasATOMICS bool // Atomic memory operation instruction set
|
||||||
|
HasFPHP bool // Half precision floating-point instruction set
|
||||||
|
HasASIMDHP bool // Advanced SIMD half precision instruction set
|
||||||
|
HasCPUID bool // CPUID identification scheme registers
|
||||||
|
HasASIMDRDM bool // Rounding double multiply add/subtract instruction set
|
||||||
|
HasJSCVT bool // Javascript conversion from floating-point to integer
|
||||||
|
HasFCMA bool // Floating-point multiplication and addition of complex numbers
|
||||||
|
HasLRCPC bool // Release Consistent processor consistent support
|
||||||
|
HasDCPOP bool // Persistent memory support
|
||||||
|
HasSHA3 bool // SHA3 hardware implementation
|
||||||
|
HasSM3 bool // SM3 hardware implementation
|
||||||
|
HasSM4 bool // SM4 hardware implementation
|
||||||
|
HasASIMDDP bool // Advanced SIMD double precision instruction set
|
||||||
|
HasSHA512 bool // SHA512 hardware implementation
|
||||||
|
HasSVE bool // Scalable Vector Extensions
|
||||||
|
HasSVE2 bool // Scalable Vector Extensions 2
|
||||||
|
HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32
|
||||||
|
HasDIT bool // Data Independent Timing support
|
||||||
|
HasI8MM bool // Advanced SIMD Int8 matrix multiplication instructions
|
||||||
|
_ CacheLinePad
|
||||||
|
}
|
||||||
|
|
||||||
|
// ARM contains the supported CPU features of the current ARM (32-bit) platform.
|
||||||
|
// All feature flags are false if:
|
||||||
|
// 1. the current platform is not arm, or
|
||||||
|
// 2. the current operating system is not Linux.
|
||||||
|
var ARM struct {
|
||||||
|
_ CacheLinePad
|
||||||
|
HasSWP bool // SWP instruction support
|
||||||
|
HasHALF bool // Half-word load and store support
|
||||||
|
HasTHUMB bool // ARM Thumb instruction set
|
||||||
|
Has26BIT bool // Address space limited to 26-bits
|
||||||
|
HasFASTMUL bool // 32-bit operand, 64-bit result multiplication support
|
||||||
|
HasFPA bool // Floating point arithmetic support
|
||||||
|
HasVFP bool // Vector floating point support
|
||||||
|
HasEDSP bool // DSP Extensions support
|
||||||
|
HasJAVA bool // Java instruction set
|
||||||
|
HasIWMMXT bool // Intel Wireless MMX technology support
|
||||||
|
HasCRUNCH bool // MaverickCrunch context switching and handling
|
||||||
|
HasTHUMBEE bool // Thumb EE instruction set
|
||||||
|
HasNEON bool // NEON instruction set
|
||||||
|
HasVFPv3 bool // Vector floating point version 3 support
|
||||||
|
HasVFPv3D16 bool // Vector floating point version 3 D8-D15
|
||||||
|
HasTLS bool // Thread local storage support
|
||||||
|
HasVFPv4 bool // Vector floating point version 4 support
|
||||||
|
HasIDIVA bool // Integer divide instruction support in ARM mode
|
||||||
|
HasIDIVT bool // Integer divide instruction support in Thumb mode
|
||||||
|
HasVFPD32 bool // Vector floating point version 3 D15-D31
|
||||||
|
HasLPAE bool // Large Physical Address Extensions
|
||||||
|
HasEVTSTRM bool // Event stream support
|
||||||
|
HasAES bool // AES hardware implementation
|
||||||
|
HasPMULL bool // Polynomial multiplication instruction set
|
||||||
|
HasSHA1 bool // SHA1 hardware implementation
|
||||||
|
HasSHA2 bool // SHA2 hardware implementation
|
||||||
|
HasCRC32 bool // CRC32 hardware implementation
|
||||||
|
_ CacheLinePad
|
||||||
|
}
|
||||||
|
|
||||||
|
// MIPS64X contains the supported CPU features of the current mips64/mips64le
|
||||||
|
// platforms. If the current platform is not mips64/mips64le or the current
|
||||||
|
// operating system is not Linux then all feature flags are false.
|
||||||
|
var MIPS64X struct {
|
||||||
|
_ CacheLinePad
|
||||||
|
HasMSA bool // MIPS SIMD architecture
|
||||||
|
_ CacheLinePad
|
||||||
|
}
|
||||||
|
|
||||||
|
// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms.
|
||||||
|
// If the current platform is not ppc64/ppc64le then all feature flags are false.
|
||||||
|
//
|
||||||
|
// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00,
|
||||||
|
// since there are no optional categories. There are some exceptions that also
|
||||||
|
// require kernel support to work (DARN, SCV), so there are feature bits for
|
||||||
|
// those as well. The struct is padded to avoid false sharing.
|
||||||
|
var PPC64 struct {
|
||||||
|
_ CacheLinePad
|
||||||
|
HasDARN bool // Hardware random number generator (requires kernel enablement)
|
||||||
|
HasSCV bool // Syscall vectored (requires kernel enablement)
|
||||||
|
IsPOWER8 bool // ISA v2.07 (POWER8)
|
||||||
|
IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8
|
||||||
|
_ CacheLinePad
|
||||||
|
}
|
||||||
|
|
||||||
|
// S390X contains the supported CPU features of the current IBM Z
|
||||||
|
// (s390x) platform. If the current platform is not IBM Z then all
|
||||||
|
// feature flags are false.
|
||||||
|
//
|
||||||
|
// S390X is padded to avoid false sharing. Further HasVX is only set
|
||||||
|
// if the OS supports vector registers in addition to the STFLE
|
||||||
|
// feature bit being set.
|
||||||
|
var S390X struct {
|
||||||
|
_ CacheLinePad
|
||||||
|
HasZARCH bool // z/Architecture mode is active [mandatory]
|
||||||
|
HasSTFLE bool // store facility list extended
|
||||||
|
HasLDISP bool // long (20-bit) displacements
|
||||||
|
HasEIMM bool // 32-bit immediates
|
||||||
|
HasDFP bool // decimal floating point
|
||||||
|
HasETF3EH bool // ETF-3 enhanced
|
||||||
|
HasMSA bool // message security assist (CPACF)
|
||||||
|
HasAES bool // KM-AES{128,192,256} functions
|
||||||
|
HasAESCBC bool // KMC-AES{128,192,256} functions
|
||||||
|
HasAESCTR bool // KMCTR-AES{128,192,256} functions
|
||||||
|
HasAESGCM bool // KMA-GCM-AES{128,192,256} functions
|
||||||
|
HasGHASH bool // KIMD-GHASH function
|
||||||
|
HasSHA1 bool // K{I,L}MD-SHA-1 functions
|
||||||
|
HasSHA256 bool // K{I,L}MD-SHA-256 functions
|
||||||
|
HasSHA512 bool // K{I,L}MD-SHA-512 functions
|
||||||
|
HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions
|
||||||
|
HasVX bool // vector facility
|
||||||
|
HasVXE bool // vector-enhancements facility 1
|
||||||
|
_ CacheLinePad
|
||||||
|
}
|
||||||
|
|
||||||
|
// RISCV64 contains the supported CPU features and performance characteristics for riscv64
|
||||||
|
// platforms. The booleans in RISCV64, with the exception of HasFastMisaligned, indicate
|
||||||
|
// the presence of RISC-V extensions.
|
||||||
|
//
|
||||||
|
// It is safe to assume that all the RV64G extensions are supported and so they are omitted from
|
||||||
|
// this structure. As riscv64 Go programs require at least RV64G, the code that populates
|
||||||
|
// this structure cannot run successfully if some of the RV64G extensions are missing.
|
||||||
|
// The struct is padded to avoid false sharing.
|
||||||
|
var RISCV64 struct {
|
||||||
|
_ CacheLinePad
|
||||||
|
HasFastMisaligned bool // Fast misaligned accesses
|
||||||
|
HasC bool // Compressed instruction-set extension
|
||||||
|
HasV bool // Vector extension compatible with RVV 1.0
|
||||||
|
HasZba bool // Address generation instructions extension
|
||||||
|
HasZbb bool // Basic bit-manipulation extension
|
||||||
|
HasZbs bool // Single-bit instructions extension
|
||||||
|
_ CacheLinePad
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
archInit()
|
||||||
|
initOptions()
|
||||||
|
processOptions()
|
||||||
|
}
|
||||||
|
|
||||||
|
// options contains the cpu debug options that can be used in GODEBUG.
|
||||||
|
// Options are arch dependent and are added by the arch specific initOptions functions.
|
||||||
|
// Features that are mandatory for the specific GOARCH should have the Required field set
|
||||||
|
// (e.g. SSE2 on amd64).
|
||||||
|
var options []option
|
||||||
|
|
||||||
|
// Option names should be lower case. e.g. avx instead of AVX.
|
||||||
|
type option struct {
|
||||||
|
Name string
|
||||||
|
Feature *bool
|
||||||
|
Specified bool // whether feature value was specified in GODEBUG
|
||||||
|
Enable bool // whether feature should be enabled
|
||||||
|
Required bool // whether feature is mandatory and can not be disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
func processOptions() {
|
||||||
|
env := os.Getenv("GODEBUG")
|
||||||
|
field:
|
||||||
|
for env != "" {
|
||||||
|
field := ""
|
||||||
|
i := strings.IndexByte(env, ',')
|
||||||
|
if i < 0 {
|
||||||
|
field, env = env, ""
|
||||||
|
} else {
|
||||||
|
field, env = env[:i], env[i+1:]
|
||||||
|
}
|
||||||
|
if len(field) < 4 || field[:4] != "cpu." {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
i = strings.IndexByte(field, '=')
|
||||||
|
if i < 0 {
|
||||||
|
print("GODEBUG sys/cpu: no value specified for \"", field, "\"\n")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on"
|
||||||
|
|
||||||
|
var enable bool
|
||||||
|
switch value {
|
||||||
|
case "on":
|
||||||
|
enable = true
|
||||||
|
case "off":
|
||||||
|
enable = false
|
||||||
|
default:
|
||||||
|
print("GODEBUG sys/cpu: value \"", value, "\" not supported for cpu option \"", key, "\"\n")
|
||||||
|
continue field
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == "all" {
|
||||||
|
for i := range options {
|
||||||
|
options[i].Specified = true
|
||||||
|
options[i].Enable = enable || options[i].Required
|
||||||
|
}
|
||||||
|
continue field
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range options {
|
||||||
|
if options[i].Name == key {
|
||||||
|
options[i].Specified = true
|
||||||
|
options[i].Enable = enable
|
||||||
|
continue field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print("GODEBUG sys/cpu: unknown cpu feature \"", key, "\"\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range options {
|
||||||
|
if !o.Specified {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.Enable && !*o.Feature {
|
||||||
|
print("GODEBUG sys/cpu: can not enable \"", o.Name, "\", missing CPU support\n")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !o.Enable && o.Required {
|
||||||
|
print("GODEBUG sys/cpu: can not disable \"", o.Name, "\", required CPU feature\n")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
*o.Feature = o.Enable
|
||||||
|
}
|
||||||
|
}
|
33
internal/deps/cpu/cpu_aix.go
Normal file
33
internal/deps/cpu/cpu_aix.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build aix
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
const (
|
||||||
|
// getsystemcfg constants
|
||||||
|
_SC_IMPL = 2
|
||||||
|
_IMPL_POWER8 = 0x10000
|
||||||
|
_IMPL_POWER9 = 0x20000
|
||||||
|
)
|
||||||
|
|
||||||
|
func archInit() {
|
||||||
|
impl := getsystemcfg(_SC_IMPL)
|
||||||
|
if impl&_IMPL_POWER8 != 0 {
|
||||||
|
PPC64.IsPOWER8 = true
|
||||||
|
}
|
||||||
|
if impl&_IMPL_POWER9 != 0 {
|
||||||
|
PPC64.IsPOWER8 = true
|
||||||
|
PPC64.IsPOWER9 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Initialized = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func getsystemcfg(label int) (n uint64) {
|
||||||
|
r0, _ := callgetsystemcfg(label)
|
||||||
|
n = uint64(r0)
|
||||||
|
return
|
||||||
|
}
|
72
internal/deps/cpu/cpu_arm.go
Normal file
72
internal/deps/cpu/cpu_arm.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
const cacheLineSize = 32
|
||||||
|
|
||||||
|
// HWCAP/HWCAP2 bits.
|
||||||
|
// These are specific to Linux.
|
||||||
|
const (
|
||||||
|
hwcap_SWP = 1 << 0
|
||||||
|
hwcap_HALF = 1 << 1
|
||||||
|
hwcap_THUMB = 1 << 2
|
||||||
|
hwcap_26BIT = 1 << 3
|
||||||
|
hwcap_FAST_MULT = 1 << 4
|
||||||
|
hwcap_FPA = 1 << 5
|
||||||
|
hwcap_VFP = 1 << 6
|
||||||
|
hwcap_EDSP = 1 << 7
|
||||||
|
hwcap_JAVA = 1 << 8
|
||||||
|
hwcap_IWMMXT = 1 << 9
|
||||||
|
hwcap_CRUNCH = 1 << 10
|
||||||
|
hwcap_THUMBEE = 1 << 11
|
||||||
|
hwcap_NEON = 1 << 12
|
||||||
|
hwcap_VFPv3 = 1 << 13
|
||||||
|
hwcap_VFPv3D16 = 1 << 14
|
||||||
|
hwcap_TLS = 1 << 15
|
||||||
|
hwcap_VFPv4 = 1 << 16
|
||||||
|
hwcap_IDIVA = 1 << 17
|
||||||
|
hwcap_IDIVT = 1 << 18
|
||||||
|
hwcap_VFPD32 = 1 << 19
|
||||||
|
hwcap_LPAE = 1 << 20
|
||||||
|
hwcap_EVTSTRM = 1 << 21
|
||||||
|
|
||||||
|
hwcap2_AES = 1 << 0
|
||||||
|
hwcap2_PMULL = 1 << 1
|
||||||
|
hwcap2_SHA1 = 1 << 2
|
||||||
|
hwcap2_SHA2 = 1 << 3
|
||||||
|
hwcap2_CRC32 = 1 << 4
|
||||||
|
)
|
||||||
|
|
||||||
|
func initOptions() {
|
||||||
|
options = []option{
|
||||||
|
{Name: "pmull", Feature: &ARM.HasPMULL},
|
||||||
|
{Name: "sha1", Feature: &ARM.HasSHA1},
|
||||||
|
{Name: "sha2", Feature: &ARM.HasSHA2},
|
||||||
|
{Name: "swp", Feature: &ARM.HasSWP},
|
||||||
|
{Name: "thumb", Feature: &ARM.HasTHUMB},
|
||||||
|
{Name: "thumbee", Feature: &ARM.HasTHUMBEE},
|
||||||
|
{Name: "tls", Feature: &ARM.HasTLS},
|
||||||
|
{Name: "vfp", Feature: &ARM.HasVFP},
|
||||||
|
{Name: "vfpd32", Feature: &ARM.HasVFPD32},
|
||||||
|
{Name: "vfpv3", Feature: &ARM.HasVFPv3},
|
||||||
|
{Name: "vfpv3d16", Feature: &ARM.HasVFPv3D16},
|
||||||
|
{Name: "vfpv4", Feature: &ARM.HasVFPv4},
|
||||||
|
{Name: "half", Feature: &ARM.HasHALF},
|
||||||
|
{Name: "26bit", Feature: &ARM.Has26BIT},
|
||||||
|
{Name: "fastmul", Feature: &ARM.HasFASTMUL},
|
||||||
|
{Name: "fpa", Feature: &ARM.HasFPA},
|
||||||
|
{Name: "edsp", Feature: &ARM.HasEDSP},
|
||||||
|
{Name: "java", Feature: &ARM.HasJAVA},
|
||||||
|
{Name: "iwmmxt", Feature: &ARM.HasIWMMXT},
|
||||||
|
{Name: "crunch", Feature: &ARM.HasCRUNCH},
|
||||||
|
{Name: "neon", Feature: &ARM.HasNEON},
|
||||||
|
{Name: "idivt", Feature: &ARM.HasIDIVT},
|
||||||
|
{Name: "idiva", Feature: &ARM.HasIDIVA},
|
||||||
|
{Name: "lpae", Feature: &ARM.HasLPAE},
|
||||||
|
{Name: "evtstrm", Feature: &ARM.HasEVTSTRM},
|
||||||
|
{Name: "aes", Feature: &ARM.HasAES},
|
||||||
|
{Name: "crc32", Feature: &ARM.HasCRC32},
|
||||||
|
}
|
||||||
|
}
|
194
internal/deps/cpu/cpu_arm64.go
Normal file
194
internal/deps/cpu/cpu_arm64.go
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import "runtime"
|
||||||
|
|
||||||
|
// cacheLineSize is used to prevent false sharing of cache lines.
|
||||||
|
// We choose 128 because Apple Silicon, a.k.a. M1, has 128-byte cache line size.
|
||||||
|
// It doesn't cost much and is much more future-proof.
|
||||||
|
const cacheLineSize = 128
|
||||||
|
|
||||||
|
func initOptions() {
|
||||||
|
options = []option{
|
||||||
|
{Name: "fp", Feature: &ARM64.HasFP},
|
||||||
|
{Name: "asimd", Feature: &ARM64.HasASIMD},
|
||||||
|
{Name: "evstrm", Feature: &ARM64.HasEVTSTRM},
|
||||||
|
{Name: "aes", Feature: &ARM64.HasAES},
|
||||||
|
{Name: "fphp", Feature: &ARM64.HasFPHP},
|
||||||
|
{Name: "jscvt", Feature: &ARM64.HasJSCVT},
|
||||||
|
{Name: "lrcpc", Feature: &ARM64.HasLRCPC},
|
||||||
|
{Name: "pmull", Feature: &ARM64.HasPMULL},
|
||||||
|
{Name: "sha1", Feature: &ARM64.HasSHA1},
|
||||||
|
{Name: "sha2", Feature: &ARM64.HasSHA2},
|
||||||
|
{Name: "sha3", Feature: &ARM64.HasSHA3},
|
||||||
|
{Name: "sha512", Feature: &ARM64.HasSHA512},
|
||||||
|
{Name: "sm3", Feature: &ARM64.HasSM3},
|
||||||
|
{Name: "sm4", Feature: &ARM64.HasSM4},
|
||||||
|
{Name: "sve", Feature: &ARM64.HasSVE},
|
||||||
|
{Name: "sve2", Feature: &ARM64.HasSVE2},
|
||||||
|
{Name: "crc32", Feature: &ARM64.HasCRC32},
|
||||||
|
{Name: "atomics", Feature: &ARM64.HasATOMICS},
|
||||||
|
{Name: "asimdhp", Feature: &ARM64.HasASIMDHP},
|
||||||
|
{Name: "cpuid", Feature: &ARM64.HasCPUID},
|
||||||
|
{Name: "asimrdm", Feature: &ARM64.HasASIMDRDM},
|
||||||
|
{Name: "fcma", Feature: &ARM64.HasFCMA},
|
||||||
|
{Name: "dcpop", Feature: &ARM64.HasDCPOP},
|
||||||
|
{Name: "asimddp", Feature: &ARM64.HasASIMDDP},
|
||||||
|
{Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM},
|
||||||
|
{Name: "dit", Feature: &ARM64.HasDIT},
|
||||||
|
{Name: "i8mm", Feature: &ARM64.HasI8MM},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func archInit() {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "freebsd":
|
||||||
|
readARM64Registers()
|
||||||
|
case "linux", "netbsd", "openbsd":
|
||||||
|
doinit()
|
||||||
|
default:
|
||||||
|
// Many platforms don't seem to allow reading these registers.
|
||||||
|
setMinimalFeatures()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setMinimalFeatures fakes the minimal ARM64 features expected by
|
||||||
|
// TestARM64minimalFeatures.
|
||||||
|
func setMinimalFeatures() {
|
||||||
|
ARM64.HasASIMD = true
|
||||||
|
ARM64.HasFP = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func readARM64Registers() {
|
||||||
|
Initialized = true
|
||||||
|
|
||||||
|
parseARM64SystemRegisters(getisar0(), getisar1(), getpfr0())
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) {
|
||||||
|
// ID_AA64ISAR0_EL1
|
||||||
|
switch extractBits(isar0, 4, 7) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasAES = true
|
||||||
|
case 2:
|
||||||
|
ARM64.HasAES = true
|
||||||
|
ARM64.HasPMULL = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar0, 8, 11) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasSHA1 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar0, 12, 15) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasSHA2 = true
|
||||||
|
case 2:
|
||||||
|
ARM64.HasSHA2 = true
|
||||||
|
ARM64.HasSHA512 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar0, 16, 19) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasCRC32 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar0, 20, 23) {
|
||||||
|
case 2:
|
||||||
|
ARM64.HasATOMICS = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar0, 28, 31) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasASIMDRDM = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar0, 32, 35) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasSHA3 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar0, 36, 39) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasSM3 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar0, 40, 43) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasSM4 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar0, 44, 47) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasASIMDDP = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID_AA64ISAR1_EL1
|
||||||
|
switch extractBits(isar1, 0, 3) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasDCPOP = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar1, 12, 15) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasJSCVT = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar1, 16, 19) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasFCMA = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar1, 20, 23) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasLRCPC = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(isar1, 52, 55) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasI8MM = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID_AA64PFR0_EL1
|
||||||
|
switch extractBits(pfr0, 16, 19) {
|
||||||
|
case 0:
|
||||||
|
ARM64.HasFP = true
|
||||||
|
case 1:
|
||||||
|
ARM64.HasFP = true
|
||||||
|
ARM64.HasFPHP = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(pfr0, 20, 23) {
|
||||||
|
case 0:
|
||||||
|
ARM64.HasASIMD = true
|
||||||
|
case 1:
|
||||||
|
ARM64.HasASIMD = true
|
||||||
|
ARM64.HasASIMDHP = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(pfr0, 32, 35) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasSVE = true
|
||||||
|
|
||||||
|
parseARM64SVERegister(getzfr0())
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extractBits(pfr0, 48, 51) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasDIT = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseARM64SVERegister(zfr0 uint64) {
|
||||||
|
switch extractBits(zfr0, 0, 3) {
|
||||||
|
case 1:
|
||||||
|
ARM64.HasSVE2 = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractBits(data uint64, start, end uint) uint {
|
||||||
|
return (uint)(data>>start) & ((1 << (end - start + 1)) - 1)
|
||||||
|
}
|
39
internal/deps/cpu/cpu_arm64.s
Normal file
39
internal/deps/cpu/cpu_arm64.s
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build gc
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func getisar0() uint64
|
||||||
|
TEXT ·getisar0(SB),NOSPLIT,$0-8
|
||||||
|
// get Instruction Set Attributes 0 into x0
|
||||||
|
// mrs x0, ID_AA64ISAR0_EL1 = d5380600
|
||||||
|
WORD $0xd5380600
|
||||||
|
MOVD R0, ret+0(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func getisar1() uint64
|
||||||
|
TEXT ·getisar1(SB),NOSPLIT,$0-8
|
||||||
|
// get Instruction Set Attributes 1 into x0
|
||||||
|
// mrs x0, ID_AA64ISAR1_EL1 = d5380620
|
||||||
|
WORD $0xd5380620
|
||||||
|
MOVD R0, ret+0(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func getpfr0() uint64
|
||||||
|
TEXT ·getpfr0(SB),NOSPLIT,$0-8
|
||||||
|
// get Processor Feature Register 0 into x0
|
||||||
|
// mrs x0, ID_AA64PFR0_EL1 = d5380400
|
||||||
|
WORD $0xd5380400
|
||||||
|
MOVD R0, ret+0(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func getzfr0() uint64
|
||||||
|
TEXT ·getzfr0(SB),NOSPLIT,$0-8
|
||||||
|
// get SVE Feature Register 0 into x0
|
||||||
|
// mrs x0, ID_AA64ZFR0_EL1 = d5380480
|
||||||
|
WORD $0xd5380480
|
||||||
|
MOVD R0, ret+0(FP)
|
||||||
|
RET
|
61
internal/deps/cpu/cpu_darwin_x86.go
Normal file
61
internal/deps/cpu/cpu_darwin_x86.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2024 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build darwin && amd64 && gc
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
// darwinSupportsAVX512 checks Darwin kernel for AVX512 support via sysctl
|
||||||
|
// call (see issue 43089). It also restricts AVX512 support for Darwin to
|
||||||
|
// kernel version 21.3.0 (MacOS 12.2.0) or later (see issue 49233).
|
||||||
|
//
|
||||||
|
// Background:
|
||||||
|
// Darwin implements a special mechanism to economize on thread state when
|
||||||
|
// AVX512 specific registers are not in use. This scheme minimizes state when
|
||||||
|
// preempting threads that haven't yet used any AVX512 instructions, but adds
|
||||||
|
// special requirements to check for AVX512 hardware support at runtime (e.g.
|
||||||
|
// via sysctl call or commpage inspection). See issue 43089 and link below for
|
||||||
|
// full background:
|
||||||
|
// https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.1.10/osfmk/i386/fpu.c#L214-L240
|
||||||
|
//
|
||||||
|
// Additionally, all versions of the Darwin kernel from 19.6.0 through 21.2.0
|
||||||
|
// (corresponding to MacOS 10.15.6 - 12.1) have a bug that can cause corruption
|
||||||
|
// of the AVX512 mask registers (K0-K7) upon signal return. For this reason
|
||||||
|
// AVX512 is considered unsafe to use on Darwin for kernel versions prior to
|
||||||
|
// 21.3.0, where a fix has been confirmed. See issue 49233 for full background.
|
||||||
|
func darwinSupportsAVX512() bool {
|
||||||
|
return darwinSysctlEnabled([]byte("hw.optional.avx512f\x00")) && darwinKernelVersionCheck(21, 3, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure Darwin kernel version is at least major.minor.patch, avoiding dependencies
|
||||||
|
func darwinKernelVersionCheck(major, minor, patch int) bool {
|
||||||
|
var release [256]byte
|
||||||
|
err := darwinOSRelease(&release)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var mmp [3]int
|
||||||
|
c := 0
|
||||||
|
Loop:
|
||||||
|
for _, b := range release[:] {
|
||||||
|
switch {
|
||||||
|
case b >= '0' && b <= '9':
|
||||||
|
mmp[c] = 10*mmp[c] + int(b-'0')
|
||||||
|
case b == '.':
|
||||||
|
c++
|
||||||
|
if c > 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case b == 0:
|
||||||
|
break Loop
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c != 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return mmp[0] > major || mmp[0] == major && (mmp[1] > minor || mmp[1] == minor && mmp[2] >= patch)
|
||||||
|
}
|
12
internal/deps/cpu/cpu_gc_arm64.go
Normal file
12
internal/deps/cpu/cpu_gc_arm64.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build gc
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func getisar0() uint64
|
||||||
|
func getisar1() uint64
|
||||||
|
func getpfr0() uint64
|
||||||
|
func getzfr0() uint64
|
21
internal/deps/cpu/cpu_gc_s390x.go
Normal file
21
internal/deps/cpu/cpu_gc_s390x.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build gc
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
// haveAsmFunctions reports whether the other functions in this file can
|
||||||
|
// be safely called.
|
||||||
|
func haveAsmFunctions() bool { return true }
|
||||||
|
|
||||||
|
// The following feature detection functions are defined in cpu_s390x.s.
|
||||||
|
// They are likely to be expensive to call so the results should be cached.
|
||||||
|
func stfle() facilityList
|
||||||
|
func kmQuery() queryResult
|
||||||
|
func kmcQuery() queryResult
|
||||||
|
func kmctrQuery() queryResult
|
||||||
|
func kmaQuery() queryResult
|
||||||
|
func kimdQuery() queryResult
|
||||||
|
func klmdQuery() queryResult
|
15
internal/deps/cpu/cpu_gc_x86.go
Normal file
15
internal/deps/cpu/cpu_gc_x86.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build (386 || amd64 || amd64p32) && gc
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
// cpuid is implemented in cpu_gc_x86.s for gc compiler
|
||||||
|
// and in cpu_gccgo.c for gccgo.
|
||||||
|
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
||||||
|
|
||||||
|
// xgetbv with ecx = 0 is implemented in cpu_gc_x86.s for gc compiler
|
||||||
|
// and in cpu_gccgo.c for gccgo.
|
||||||
|
func xgetbv() (eax, edx uint32)
|
26
internal/deps/cpu/cpu_gc_x86.s
Normal file
26
internal/deps/cpu/cpu_gc_x86.s
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build (386 || amd64 || amd64p32) && gc
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
||||||
|
TEXT ·cpuid(SB), NOSPLIT, $0-24
|
||||||
|
MOVL eaxArg+0(FP), AX
|
||||||
|
MOVL ecxArg+4(FP), CX
|
||||||
|
CPUID
|
||||||
|
MOVL AX, eax+8(FP)
|
||||||
|
MOVL BX, ebx+12(FP)
|
||||||
|
MOVL CX, ecx+16(FP)
|
||||||
|
MOVL DX, edx+20(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func xgetbv() (eax, edx uint32)
|
||||||
|
TEXT ·xgetbv(SB), NOSPLIT, $0-8
|
||||||
|
MOVL $0, CX
|
||||||
|
XGETBV
|
||||||
|
MOVL AX, eax+0(FP)
|
||||||
|
MOVL DX, edx+4(FP)
|
||||||
|
RET
|
11
internal/deps/cpu/cpu_gccgo_arm64.go
Normal file
11
internal/deps/cpu/cpu_gccgo_arm64.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build gccgo
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func getisar0() uint64 { return 0 }
|
||||||
|
func getisar1() uint64 { return 0 }
|
||||||
|
func getpfr0() uint64 { return 0 }
|
22
internal/deps/cpu/cpu_gccgo_s390x.go
Normal file
22
internal/deps/cpu/cpu_gccgo_s390x.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build gccgo
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
// haveAsmFunctions reports whether the other functions in this file can
|
||||||
|
// be safely called.
|
||||||
|
func haveAsmFunctions() bool { return false }
|
||||||
|
|
||||||
|
// TODO(mundaym): the following feature detection functions are currently
|
||||||
|
// stubs. See https://golang.org/cl/162887 for how to fix this.
|
||||||
|
// They are likely to be expensive to call so the results should be cached.
|
||||||
|
func stfle() facilityList { panic("not implemented for gccgo") }
|
||||||
|
func kmQuery() queryResult { panic("not implemented for gccgo") }
|
||||||
|
func kmcQuery() queryResult { panic("not implemented for gccgo") }
|
||||||
|
func kmctrQuery() queryResult { panic("not implemented for gccgo") }
|
||||||
|
func kmaQuery() queryResult { panic("not implemented for gccgo") }
|
||||||
|
func kimdQuery() queryResult { panic("not implemented for gccgo") }
|
||||||
|
func klmdQuery() queryResult { panic("not implemented for gccgo") }
|
37
internal/deps/cpu/cpu_gccgo_x86.c
Normal file
37
internal/deps/cpu/cpu_gccgo_x86.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build (386 || amd64 || amd64p32) && gccgo
|
||||||
|
|
||||||
|
#include <cpuid.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <x86intrin.h>
|
||||||
|
|
||||||
|
// Need to wrap __get_cpuid_count because it's declared as static.
|
||||||
|
int
|
||||||
|
gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf,
|
||||||
|
uint32_t *eax, uint32_t *ebx,
|
||||||
|
uint32_t *ecx, uint32_t *edx)
|
||||||
|
{
|
||||||
|
return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC target("xsave")
|
||||||
|
#pragma clang attribute push (__attribute__((target("xsave"))), apply_to=function)
|
||||||
|
|
||||||
|
// xgetbv reads the contents of an XCR (Extended Control Register)
|
||||||
|
// specified in the ECX register into registers EDX:EAX.
|
||||||
|
// Currently, the only supported value for XCR is 0.
|
||||||
|
void
|
||||||
|
gccgoXgetbv(uint32_t *eax, uint32_t *edx)
|
||||||
|
{
|
||||||
|
uint64_t v = _xgetbv(0);
|
||||||
|
*eax = v & 0xffffffff;
|
||||||
|
*edx = v >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma clang attribute pop
|
||||||
|
#pragma GCC pop_options
|
25
internal/deps/cpu/cpu_gccgo_x86.go
Normal file
25
internal/deps/cpu/cpu_gccgo_x86.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build (386 || amd64 || amd64p32) && gccgo
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
//extern gccgoGetCpuidCount
|
||||||
|
func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32)
|
||||||
|
|
||||||
|
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) {
|
||||||
|
var a, b, c, d uint32
|
||||||
|
gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d)
|
||||||
|
return a, b, c, d
|
||||||
|
}
|
||||||
|
|
||||||
|
//extern gccgoXgetbv
|
||||||
|
func gccgoXgetbv(eax, edx *uint32)
|
||||||
|
|
||||||
|
func xgetbv() (eax, edx uint32) {
|
||||||
|
var a, d uint32
|
||||||
|
gccgoXgetbv(&a, &d)
|
||||||
|
return a, d
|
||||||
|
}
|
15
internal/deps/cpu/cpu_linux.go
Normal file
15
internal/deps/cpu/cpu_linux.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !386 && !amd64 && !amd64p32 && !arm64
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func archInit() {
|
||||||
|
if err := readHWCAP(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
doinit()
|
||||||
|
Initialized = true
|
||||||
|
}
|
39
internal/deps/cpu/cpu_linux_arm.go
Normal file
39
internal/deps/cpu/cpu_linux_arm.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func doinit() {
|
||||||
|
ARM.HasSWP = isSet(hwCap, hwcap_SWP)
|
||||||
|
ARM.HasHALF = isSet(hwCap, hwcap_HALF)
|
||||||
|
ARM.HasTHUMB = isSet(hwCap, hwcap_THUMB)
|
||||||
|
ARM.Has26BIT = isSet(hwCap, hwcap_26BIT)
|
||||||
|
ARM.HasFASTMUL = isSet(hwCap, hwcap_FAST_MULT)
|
||||||
|
ARM.HasFPA = isSet(hwCap, hwcap_FPA)
|
||||||
|
ARM.HasVFP = isSet(hwCap, hwcap_VFP)
|
||||||
|
ARM.HasEDSP = isSet(hwCap, hwcap_EDSP)
|
||||||
|
ARM.HasJAVA = isSet(hwCap, hwcap_JAVA)
|
||||||
|
ARM.HasIWMMXT = isSet(hwCap, hwcap_IWMMXT)
|
||||||
|
ARM.HasCRUNCH = isSet(hwCap, hwcap_CRUNCH)
|
||||||
|
ARM.HasTHUMBEE = isSet(hwCap, hwcap_THUMBEE)
|
||||||
|
ARM.HasNEON = isSet(hwCap, hwcap_NEON)
|
||||||
|
ARM.HasVFPv3 = isSet(hwCap, hwcap_VFPv3)
|
||||||
|
ARM.HasVFPv3D16 = isSet(hwCap, hwcap_VFPv3D16)
|
||||||
|
ARM.HasTLS = isSet(hwCap, hwcap_TLS)
|
||||||
|
ARM.HasVFPv4 = isSet(hwCap, hwcap_VFPv4)
|
||||||
|
ARM.HasIDIVA = isSet(hwCap, hwcap_IDIVA)
|
||||||
|
ARM.HasIDIVT = isSet(hwCap, hwcap_IDIVT)
|
||||||
|
ARM.HasVFPD32 = isSet(hwCap, hwcap_VFPD32)
|
||||||
|
ARM.HasLPAE = isSet(hwCap, hwcap_LPAE)
|
||||||
|
ARM.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM)
|
||||||
|
ARM.HasAES = isSet(hwCap2, hwcap2_AES)
|
||||||
|
ARM.HasPMULL = isSet(hwCap2, hwcap2_PMULL)
|
||||||
|
ARM.HasSHA1 = isSet(hwCap2, hwcap2_SHA1)
|
||||||
|
ARM.HasSHA2 = isSet(hwCap2, hwcap2_SHA2)
|
||||||
|
ARM.HasCRC32 = isSet(hwCap2, hwcap2_CRC32)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSet(hwc uint, value uint) bool {
|
||||||
|
return hwc&value != 0
|
||||||
|
}
|
120
internal/deps/cpu/cpu_linux_arm64.go
Normal file
120
internal/deps/cpu/cpu_linux_arm64.go
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HWCAP/HWCAP2 bits. These are exposed by Linux.
|
||||||
|
const (
|
||||||
|
hwcap_FP = 1 << 0
|
||||||
|
hwcap_ASIMD = 1 << 1
|
||||||
|
hwcap_EVTSTRM = 1 << 2
|
||||||
|
hwcap_AES = 1 << 3
|
||||||
|
hwcap_PMULL = 1 << 4
|
||||||
|
hwcap_SHA1 = 1 << 5
|
||||||
|
hwcap_SHA2 = 1 << 6
|
||||||
|
hwcap_CRC32 = 1 << 7
|
||||||
|
hwcap_ATOMICS = 1 << 8
|
||||||
|
hwcap_FPHP = 1 << 9
|
||||||
|
hwcap_ASIMDHP = 1 << 10
|
||||||
|
hwcap_CPUID = 1 << 11
|
||||||
|
hwcap_ASIMDRDM = 1 << 12
|
||||||
|
hwcap_JSCVT = 1 << 13
|
||||||
|
hwcap_FCMA = 1 << 14
|
||||||
|
hwcap_LRCPC = 1 << 15
|
||||||
|
hwcap_DCPOP = 1 << 16
|
||||||
|
hwcap_SHA3 = 1 << 17
|
||||||
|
hwcap_SM3 = 1 << 18
|
||||||
|
hwcap_SM4 = 1 << 19
|
||||||
|
hwcap_ASIMDDP = 1 << 20
|
||||||
|
hwcap_SHA512 = 1 << 21
|
||||||
|
hwcap_SVE = 1 << 22
|
||||||
|
hwcap_ASIMDFHM = 1 << 23
|
||||||
|
hwcap_DIT = 1 << 24
|
||||||
|
|
||||||
|
hwcap2_SVE2 = 1 << 1
|
||||||
|
hwcap2_I8MM = 1 << 13
|
||||||
|
)
|
||||||
|
|
||||||
|
// linuxKernelCanEmulateCPUID reports whether we're running
|
||||||
|
// on Linux 4.11+. Ideally we'd like to ask the question about
|
||||||
|
// whether the current kernel contains
|
||||||
|
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=77c97b4ee21290f5f083173d957843b615abbff2
|
||||||
|
// but the version number will have to do.
|
||||||
|
func linuxKernelCanEmulateCPUID() bool {
|
||||||
|
var un syscall.Utsname
|
||||||
|
syscall.Uname(&un)
|
||||||
|
var sb strings.Builder
|
||||||
|
for _, b := range un.Release[:] {
|
||||||
|
if b == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
sb.WriteByte(byte(b))
|
||||||
|
}
|
||||||
|
major, minor, _, ok := parseRelease(sb.String())
|
||||||
|
return ok && (major > 4 || major == 4 && minor >= 11)
|
||||||
|
}
|
||||||
|
|
||||||
|
func doinit() {
|
||||||
|
if err := readHWCAP(); err != nil {
|
||||||
|
// We failed to read /proc/self/auxv. This can happen if the binary has
|
||||||
|
// been given extra capabilities(7) with /bin/setcap.
|
||||||
|
//
|
||||||
|
// When this happens, we have two options. If the Linux kernel is new
|
||||||
|
// enough (4.11+), we can read the arm64 registers directly which'll
|
||||||
|
// trap into the kernel and then return back to userspace.
|
||||||
|
//
|
||||||
|
// But on older kernels, such as Linux 4.4.180 as used on many Synology
|
||||||
|
// devices, calling readARM64Registers (specifically getisar0) will
|
||||||
|
// cause a SIGILL and we'll die. So for older kernels, parse /proc/cpuinfo
|
||||||
|
// instead.
|
||||||
|
//
|
||||||
|
// See golang/go#57336.
|
||||||
|
if linuxKernelCanEmulateCPUID() {
|
||||||
|
readARM64Registers()
|
||||||
|
} else {
|
||||||
|
readLinuxProcCPUInfo()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// HWCAP feature bits
|
||||||
|
ARM64.HasFP = isSet(hwCap, hwcap_FP)
|
||||||
|
ARM64.HasASIMD = isSet(hwCap, hwcap_ASIMD)
|
||||||
|
ARM64.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM)
|
||||||
|
ARM64.HasAES = isSet(hwCap, hwcap_AES)
|
||||||
|
ARM64.HasPMULL = isSet(hwCap, hwcap_PMULL)
|
||||||
|
ARM64.HasSHA1 = isSet(hwCap, hwcap_SHA1)
|
||||||
|
ARM64.HasSHA2 = isSet(hwCap, hwcap_SHA2)
|
||||||
|
ARM64.HasCRC32 = isSet(hwCap, hwcap_CRC32)
|
||||||
|
ARM64.HasATOMICS = isSet(hwCap, hwcap_ATOMICS)
|
||||||
|
ARM64.HasFPHP = isSet(hwCap, hwcap_FPHP)
|
||||||
|
ARM64.HasASIMDHP = isSet(hwCap, hwcap_ASIMDHP)
|
||||||
|
ARM64.HasCPUID = isSet(hwCap, hwcap_CPUID)
|
||||||
|
ARM64.HasASIMDRDM = isSet(hwCap, hwcap_ASIMDRDM)
|
||||||
|
ARM64.HasJSCVT = isSet(hwCap, hwcap_JSCVT)
|
||||||
|
ARM64.HasFCMA = isSet(hwCap, hwcap_FCMA)
|
||||||
|
ARM64.HasLRCPC = isSet(hwCap, hwcap_LRCPC)
|
||||||
|
ARM64.HasDCPOP = isSet(hwCap, hwcap_DCPOP)
|
||||||
|
ARM64.HasSHA3 = isSet(hwCap, hwcap_SHA3)
|
||||||
|
ARM64.HasSM3 = isSet(hwCap, hwcap_SM3)
|
||||||
|
ARM64.HasSM4 = isSet(hwCap, hwcap_SM4)
|
||||||
|
ARM64.HasASIMDDP = isSet(hwCap, hwcap_ASIMDDP)
|
||||||
|
ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512)
|
||||||
|
ARM64.HasSVE = isSet(hwCap, hwcap_SVE)
|
||||||
|
ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM)
|
||||||
|
ARM64.HasDIT = isSet(hwCap, hwcap_DIT)
|
||||||
|
|
||||||
|
// HWCAP2 feature bits
|
||||||
|
ARM64.HasSVE2 = isSet(hwCap2, hwcap2_SVE2)
|
||||||
|
ARM64.HasI8MM = isSet(hwCap2, hwcap2_I8MM)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSet(hwc uint, value uint) bool {
|
||||||
|
return hwc&value != 0
|
||||||
|
}
|
22
internal/deps/cpu/cpu_linux_mips64x.go
Normal file
22
internal/deps/cpu/cpu_linux_mips64x.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build linux && (mips64 || mips64le)
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
// HWCAP bits. These are exposed by the Linux kernel 5.4.
|
||||||
|
const (
|
||||||
|
// CPU features
|
||||||
|
hwcap_MIPS_MSA = 1 << 1
|
||||||
|
)
|
||||||
|
|
||||||
|
func doinit() {
|
||||||
|
// HWCAP feature bits
|
||||||
|
MIPS64X.HasMSA = isSet(hwCap, hwcap_MIPS_MSA)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSet(hwc uint, value uint) bool {
|
||||||
|
return hwc&value != 0
|
||||||
|
}
|
9
internal/deps/cpu/cpu_linux_noinit.go
Normal file
9
internal/deps/cpu/cpu_linux_noinit.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func doinit() {}
|
30
internal/deps/cpu/cpu_linux_ppc64x.go
Normal file
30
internal/deps/cpu/cpu_linux_ppc64x.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build linux && (ppc64 || ppc64le)
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
// HWCAP/HWCAP2 bits. These are exposed by the kernel.
|
||||||
|
const (
|
||||||
|
// ISA Level
|
||||||
|
_PPC_FEATURE2_ARCH_2_07 = 0x80000000
|
||||||
|
_PPC_FEATURE2_ARCH_3_00 = 0x00800000
|
||||||
|
|
||||||
|
// CPU features
|
||||||
|
_PPC_FEATURE2_DARN = 0x00200000
|
||||||
|
_PPC_FEATURE2_SCV = 0x00100000
|
||||||
|
)
|
||||||
|
|
||||||
|
func doinit() {
|
||||||
|
// HWCAP2 feature bits
|
||||||
|
PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07)
|
||||||
|
PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00)
|
||||||
|
PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN)
|
||||||
|
PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSet(hwc uint, value uint) bool {
|
||||||
|
return hwc&value != 0
|
||||||
|
}
|
137
internal/deps/cpu/cpu_linux_riscv64.go
Normal file
137
internal/deps/cpu/cpu_linux_riscv64.go
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
// Copyright 2024 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RISC-V extension discovery code for Linux. The approach here is to first try the riscv_hwprobe
|
||||||
|
// syscall falling back to HWCAP to check for the C extension if riscv_hwprobe is not available.
|
||||||
|
//
|
||||||
|
// A note on detection of the Vector extension using HWCAP.
|
||||||
|
//
|
||||||
|
// Support for the Vector extension version 1.0 was added to the Linux kernel in release 6.5.
|
||||||
|
// Support for the riscv_hwprobe syscall was added in 6.4. It follows that if the riscv_hwprobe
|
||||||
|
// syscall is not available then neither is the Vector extension (which needs kernel support).
|
||||||
|
// The riscv_hwprobe syscall should then be all we need to detect the Vector extension.
|
||||||
|
// However, some RISC-V board manufacturers ship boards with an older kernel on top of which
|
||||||
|
// they have back-ported various versions of the Vector extension patches but not the riscv_hwprobe
|
||||||
|
// patches. These kernels advertise support for the Vector extension using HWCAP. Falling
|
||||||
|
// back to HWCAP to detect the Vector extension, if riscv_hwprobe is not available, or simply not
|
||||||
|
// bothering with riscv_hwprobe at all and just using HWCAP may then seem like an attractive option.
|
||||||
|
//
|
||||||
|
// Unfortunately, simply checking the 'V' bit in AT_HWCAP will not work as this bit is used by
|
||||||
|
// RISC-V board and cloud instance providers to mean different things. The Lichee Pi 4A board
|
||||||
|
// and the Scaleway RV1 cloud instances use the 'V' bit to advertise their support for the unratified
|
||||||
|
// 0.7.1 version of the Vector Specification. The Banana Pi BPI-F3 and the CanMV-K230 board use
|
||||||
|
// it to advertise support for 1.0 of the Vector extension. Versions 0.7.1 and 1.0 of the Vector
|
||||||
|
// extension are binary incompatible. HWCAP can then not be used in isolation to populate the
|
||||||
|
// HasV field as this field indicates that the underlying CPU is compatible with RVV 1.0.
|
||||||
|
//
|
||||||
|
// There is a way at runtime to distinguish between versions 0.7.1 and 1.0 of the Vector
|
||||||
|
// specification by issuing a RVV 1.0 vsetvli instruction and checking the vill bit of the vtype
|
||||||
|
// register. This check would allow us to safely detect version 1.0 of the Vector extension
|
||||||
|
// with HWCAP, if riscv_hwprobe were not available. However, the check cannot
|
||||||
|
// be added until the assembler supports the Vector instructions.
|
||||||
|
//
|
||||||
|
// Note the riscv_hwprobe syscall does not suffer from these ambiguities by design as all of the
|
||||||
|
// extensions it advertises support for are explicitly versioned. It's also worth noting that
|
||||||
|
// the riscv_hwprobe syscall is the only way to detect multi-letter RISC-V extensions, e.g., Zba.
|
||||||
|
// These cannot be detected using HWCAP and so riscv_hwprobe must be used to detect the majority
|
||||||
|
// of RISC-V extensions.
|
||||||
|
//
|
||||||
|
// Please see https://docs.kernel.org/arch/riscv/hwprobe.html for more information.
|
||||||
|
|
||||||
|
// golang.org/x/sys/cpu is not allowed to depend on golang.org/x/sys/unix so we must
|
||||||
|
// reproduce the constants, types and functions needed to make the riscv_hwprobe syscall
|
||||||
|
// here.
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go.
|
||||||
|
riscv_HWPROBE_KEY_IMA_EXT_0 = 0x4
|
||||||
|
riscv_HWPROBE_IMA_C = 0x2
|
||||||
|
riscv_HWPROBE_IMA_V = 0x4
|
||||||
|
riscv_HWPROBE_EXT_ZBA = 0x8
|
||||||
|
riscv_HWPROBE_EXT_ZBB = 0x10
|
||||||
|
riscv_HWPROBE_EXT_ZBS = 0x20
|
||||||
|
riscv_HWPROBE_KEY_CPUPERF_0 = 0x5
|
||||||
|
riscv_HWPROBE_MISALIGNED_FAST = 0x3
|
||||||
|
riscv_HWPROBE_MISALIGNED_MASK = 0x7
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// sys_RISCV_HWPROBE is copied from golang.org/x/sys/unix/zsysnum_linux_riscv64.go.
|
||||||
|
sys_RISCV_HWPROBE = 258
|
||||||
|
)
|
||||||
|
|
||||||
|
// riscvHWProbePairs is copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go.
|
||||||
|
type riscvHWProbePairs struct {
|
||||||
|
key int64
|
||||||
|
value uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// CPU features
|
||||||
|
hwcap_RISCV_ISA_C = 1 << ('C' - 'A')
|
||||||
|
)
|
||||||
|
|
||||||
|
func doinit() {
|
||||||
|
// A slice of key/value pair structures is passed to the RISCVHWProbe syscall. The key
|
||||||
|
// field should be initialised with one of the key constants defined above, e.g.,
|
||||||
|
// RISCV_HWPROBE_KEY_IMA_EXT_0. The syscall will set the value field to the appropriate value.
|
||||||
|
// If the kernel does not recognise a key it will set the key field to -1 and the value field to 0.
|
||||||
|
|
||||||
|
pairs := []riscvHWProbePairs{
|
||||||
|
{riscv_HWPROBE_KEY_IMA_EXT_0, 0},
|
||||||
|
{riscv_HWPROBE_KEY_CPUPERF_0, 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
// This call only indicates that extensions are supported if they are implemented on all cores.
|
||||||
|
if riscvHWProbe(pairs, 0) {
|
||||||
|
if pairs[0].key != -1 {
|
||||||
|
v := uint(pairs[0].value)
|
||||||
|
RISCV64.HasC = isSet(v, riscv_HWPROBE_IMA_C)
|
||||||
|
RISCV64.HasV = isSet(v, riscv_HWPROBE_IMA_V)
|
||||||
|
RISCV64.HasZba = isSet(v, riscv_HWPROBE_EXT_ZBA)
|
||||||
|
RISCV64.HasZbb = isSet(v, riscv_HWPROBE_EXT_ZBB)
|
||||||
|
RISCV64.HasZbs = isSet(v, riscv_HWPROBE_EXT_ZBS)
|
||||||
|
}
|
||||||
|
if pairs[1].key != -1 {
|
||||||
|
v := pairs[1].value & riscv_HWPROBE_MISALIGNED_MASK
|
||||||
|
RISCV64.HasFastMisaligned = v == riscv_HWPROBE_MISALIGNED_FAST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's double check with HWCAP if the C extension does not appear to be supported.
|
||||||
|
// This may happen if we're running on a kernel older than 6.4.
|
||||||
|
|
||||||
|
if !RISCV64.HasC {
|
||||||
|
RISCV64.HasC = isSet(hwCap, hwcap_RISCV_ISA_C)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSet(hwc uint, value uint) bool {
|
||||||
|
return hwc&value != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// riscvHWProbe is a simplified version of the generated wrapper function found in
|
||||||
|
// golang.org/x/sys/unix/zsyscall_linux_riscv64.go. We simplify it by removing the
|
||||||
|
// cpuCount and cpus parameters which we do not need. We always want to pass 0 for
|
||||||
|
// these parameters here so the kernel only reports the extensions that are present
|
||||||
|
// on all cores.
|
||||||
|
func riscvHWProbe(pairs []riscvHWProbePairs, flags uint) bool {
|
||||||
|
var _zero uintptr
|
||||||
|
var p0 unsafe.Pointer
|
||||||
|
if len(pairs) > 0 {
|
||||||
|
p0 = unsafe.Pointer(&pairs[0])
|
||||||
|
} else {
|
||||||
|
p0 = unsafe.Pointer(&_zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, e1 := syscall.Syscall6(sys_RISCV_HWPROBE, uintptr(p0), uintptr(len(pairs)), uintptr(0), uintptr(0), uintptr(flags), 0)
|
||||||
|
return e1 == 0
|
||||||
|
}
|
40
internal/deps/cpu/cpu_linux_s390x.go
Normal file
40
internal/deps/cpu/cpu_linux_s390x.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
const (
|
||||||
|
// bit mask values from /usr/include/bits/hwcap.h
|
||||||
|
hwcap_ZARCH = 2
|
||||||
|
hwcap_STFLE = 4
|
||||||
|
hwcap_MSA = 8
|
||||||
|
hwcap_LDISP = 16
|
||||||
|
hwcap_EIMM = 32
|
||||||
|
hwcap_DFP = 64
|
||||||
|
hwcap_ETF3EH = 256
|
||||||
|
hwcap_VX = 2048
|
||||||
|
hwcap_VXE = 8192
|
||||||
|
)
|
||||||
|
|
||||||
|
func initS390Xbase() {
|
||||||
|
// test HWCAP bit vector
|
||||||
|
has := func(featureMask uint) bool {
|
||||||
|
return hwCap&featureMask == featureMask
|
||||||
|
}
|
||||||
|
|
||||||
|
// mandatory
|
||||||
|
S390X.HasZARCH = has(hwcap_ZARCH)
|
||||||
|
|
||||||
|
// optional
|
||||||
|
S390X.HasSTFLE = has(hwcap_STFLE)
|
||||||
|
S390X.HasLDISP = has(hwcap_LDISP)
|
||||||
|
S390X.HasEIMM = has(hwcap_EIMM)
|
||||||
|
S390X.HasETF3EH = has(hwcap_ETF3EH)
|
||||||
|
S390X.HasDFP = has(hwcap_DFP)
|
||||||
|
S390X.HasMSA = has(hwcap_MSA)
|
||||||
|
S390X.HasVX = has(hwcap_VX)
|
||||||
|
if S390X.HasVX {
|
||||||
|
S390X.HasVXE = has(hwcap_VXE)
|
||||||
|
}
|
||||||
|
}
|
12
internal/deps/cpu/cpu_loong64.go
Normal file
12
internal/deps/cpu/cpu_loong64.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build loong64
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
const cacheLineSize = 64
|
||||||
|
|
||||||
|
func initOptions() {
|
||||||
|
}
|
15
internal/deps/cpu/cpu_mips64x.go
Normal file
15
internal/deps/cpu/cpu_mips64x.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build mips64 || mips64le
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
const cacheLineSize = 32
|
||||||
|
|
||||||
|
func initOptions() {
|
||||||
|
options = []option{
|
||||||
|
{Name: "msa", Feature: &MIPS64X.HasMSA},
|
||||||
|
}
|
||||||
|
}
|
11
internal/deps/cpu/cpu_mipsx.go
Normal file
11
internal/deps/cpu/cpu_mipsx.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build mips || mipsle
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
const cacheLineSize = 32
|
||||||
|
|
||||||
|
func initOptions() {}
|
173
internal/deps/cpu/cpu_netbsd_arm64.go
Normal file
173
internal/deps/cpu/cpu_netbsd_arm64.go
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Minimal copy of functionality from x/sys/unix so the cpu package can call
|
||||||
|
// sysctl without depending on x/sys/unix.
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CTL_QUERY = -2
|
||||||
|
|
||||||
|
_SYSCTL_VERS_1 = 0x1000000
|
||||||
|
)
|
||||||
|
|
||||||
|
var _zero uintptr
|
||||||
|
|
||||||
|
func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
|
||||||
|
var _p0 unsafe.Pointer
|
||||||
|
if len(mib) > 0 {
|
||||||
|
_p0 = unsafe.Pointer(&mib[0])
|
||||||
|
} else {
|
||||||
|
_p0 = unsafe.Pointer(&_zero)
|
||||||
|
}
|
||||||
|
_, _, errno := syscall.Syscall6(
|
||||||
|
syscall.SYS___SYSCTL,
|
||||||
|
uintptr(_p0),
|
||||||
|
uintptr(len(mib)),
|
||||||
|
uintptr(unsafe.Pointer(old)),
|
||||||
|
uintptr(unsafe.Pointer(oldlen)),
|
||||||
|
uintptr(unsafe.Pointer(new)),
|
||||||
|
uintptr(newlen))
|
||||||
|
if errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type sysctlNode struct {
|
||||||
|
Flags uint32
|
||||||
|
Num int32
|
||||||
|
Name [32]int8
|
||||||
|
Ver uint32
|
||||||
|
__rsvd uint32
|
||||||
|
Un [16]byte
|
||||||
|
_sysctl_size [8]byte
|
||||||
|
_sysctl_func [8]byte
|
||||||
|
_sysctl_parent [8]byte
|
||||||
|
_sysctl_desc [8]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func sysctlNodes(mib []int32) ([]sysctlNode, error) {
|
||||||
|
var olen uintptr
|
||||||
|
|
||||||
|
// Get a list of all sysctl nodes below the given MIB by performing
|
||||||
|
// a sysctl for the given MIB with CTL_QUERY appended.
|
||||||
|
mib = append(mib, _CTL_QUERY)
|
||||||
|
qnode := sysctlNode{Flags: _SYSCTL_VERS_1}
|
||||||
|
qp := (*byte)(unsafe.Pointer(&qnode))
|
||||||
|
sz := unsafe.Sizeof(qnode)
|
||||||
|
if err := sysctl(mib, nil, &olen, qp, sz); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we know the size, get the actual nodes.
|
||||||
|
nodes := make([]sysctlNode, olen/sz)
|
||||||
|
np := (*byte)(unsafe.Pointer(&nodes[0]))
|
||||||
|
if err := sysctl(mib, np, &olen, qp, sz); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func nametomib(name string) ([]int32, error) {
|
||||||
|
// Split name into components.
|
||||||
|
var parts []string
|
||||||
|
last := 0
|
||||||
|
for i := 0; i < len(name); i++ {
|
||||||
|
if name[i] == '.' {
|
||||||
|
parts = append(parts, name[last:i])
|
||||||
|
last = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parts = append(parts, name[last:])
|
||||||
|
|
||||||
|
mib := []int32{}
|
||||||
|
// Discover the nodes and construct the MIB OID.
|
||||||
|
for partno, part := range parts {
|
||||||
|
nodes, err := sysctlNodes(mib)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, node := range nodes {
|
||||||
|
n := make([]byte, 0)
|
||||||
|
for i := range node.Name {
|
||||||
|
if node.Name[i] != 0 {
|
||||||
|
n = append(n, byte(node.Name[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if string(n) == part {
|
||||||
|
mib = append(mib, int32(node.Num))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(mib) != partno+1 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mib, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// aarch64SysctlCPUID is struct aarch64_sysctl_cpu_id from NetBSD's <aarch64/armreg.h>
|
||||||
|
type aarch64SysctlCPUID struct {
|
||||||
|
midr uint64 /* Main ID Register */
|
||||||
|
revidr uint64 /* Revision ID Register */
|
||||||
|
mpidr uint64 /* Multiprocessor Affinity Register */
|
||||||
|
aa64dfr0 uint64 /* A64 Debug Feature Register 0 */
|
||||||
|
aa64dfr1 uint64 /* A64 Debug Feature Register 1 */
|
||||||
|
aa64isar0 uint64 /* A64 Instruction Set Attribute Register 0 */
|
||||||
|
aa64isar1 uint64 /* A64 Instruction Set Attribute Register 1 */
|
||||||
|
aa64mmfr0 uint64 /* A64 Memory Model Feature Register 0 */
|
||||||
|
aa64mmfr1 uint64 /* A64 Memory Model Feature Register 1 */
|
||||||
|
aa64mmfr2 uint64 /* A64 Memory Model Feature Register 2 */
|
||||||
|
aa64pfr0 uint64 /* A64 Processor Feature Register 0 */
|
||||||
|
aa64pfr1 uint64 /* A64 Processor Feature Register 1 */
|
||||||
|
aa64zfr0 uint64 /* A64 SVE Feature ID Register 0 */
|
||||||
|
mvfr0 uint32 /* Media and VFP Feature Register 0 */
|
||||||
|
mvfr1 uint32 /* Media and VFP Feature Register 1 */
|
||||||
|
mvfr2 uint32 /* Media and VFP Feature Register 2 */
|
||||||
|
pad uint32
|
||||||
|
clidr uint64 /* Cache Level ID Register */
|
||||||
|
ctr uint64 /* Cache Type Register */
|
||||||
|
}
|
||||||
|
|
||||||
|
func sysctlCPUID(name string) (*aarch64SysctlCPUID, error) {
|
||||||
|
mib, err := nametomib(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := aarch64SysctlCPUID{}
|
||||||
|
n := unsafe.Sizeof(out)
|
||||||
|
_, _, errno := syscall.Syscall6(
|
||||||
|
syscall.SYS___SYSCTL,
|
||||||
|
uintptr(unsafe.Pointer(&mib[0])),
|
||||||
|
uintptr(len(mib)),
|
||||||
|
uintptr(unsafe.Pointer(&out)),
|
||||||
|
uintptr(unsafe.Pointer(&n)),
|
||||||
|
uintptr(0),
|
||||||
|
uintptr(0))
|
||||||
|
if errno != 0 {
|
||||||
|
return nil, errno
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func doinit() {
|
||||||
|
cpuid, err := sysctlCPUID("machdep.cpu0.cpu_id")
|
||||||
|
if err != nil {
|
||||||
|
setMinimalFeatures()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parseARM64SystemRegisters(cpuid.aa64isar0, cpuid.aa64isar1, cpuid.aa64pfr0)
|
||||||
|
|
||||||
|
Initialized = true
|
||||||
|
}
|
65
internal/deps/cpu/cpu_openbsd_arm64.go
Normal file
65
internal/deps/cpu/cpu_openbsd_arm64.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Minimal copy of functionality from x/sys/unix so the cpu package can call
|
||||||
|
// sysctl without depending on x/sys/unix.
|
||||||
|
|
||||||
|
const (
|
||||||
|
// From OpenBSD's sys/sysctl.h.
|
||||||
|
_CTL_MACHDEP = 7
|
||||||
|
|
||||||
|
// From OpenBSD's machine/cpu.h.
|
||||||
|
_CPU_ID_AA64ISAR0 = 2
|
||||||
|
_CPU_ID_AA64ISAR1 = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
// Implemented in the runtime package (runtime/sys_openbsd3.go)
|
||||||
|
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||||
|
|
||||||
|
//go:linkname syscall_syscall6 syscall.syscall6
|
||||||
|
|
||||||
|
func sysctl(mib []uint32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
|
||||||
|
_, _, errno := syscall_syscall6(libc_sysctl_trampoline_addr, uintptr(unsafe.Pointer(&mib[0])), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
|
||||||
|
if errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var libc_sysctl_trampoline_addr uintptr
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic libc_sysctl sysctl "libc.so"
|
||||||
|
|
||||||
|
func sysctlUint64(mib []uint32) (uint64, bool) {
|
||||||
|
var out uint64
|
||||||
|
nout := unsafe.Sizeof(out)
|
||||||
|
if err := sysctl(mib, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
return out, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func doinit() {
|
||||||
|
setMinimalFeatures()
|
||||||
|
|
||||||
|
// Get ID_AA64ISAR0 and ID_AA64ISAR1 from sysctl.
|
||||||
|
isar0, ok := sysctlUint64([]uint32{_CTL_MACHDEP, _CPU_ID_AA64ISAR0})
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isar1, ok := sysctlUint64([]uint32{_CTL_MACHDEP, _CPU_ID_AA64ISAR1})
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parseARM64SystemRegisters(isar0, isar1, 0)
|
||||||
|
|
||||||
|
Initialized = true
|
||||||
|
}
|
11
internal/deps/cpu/cpu_openbsd_arm64.s
Normal file
11
internal/deps/cpu/cpu_openbsd_arm64.s
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0
|
||||||
|
JMP libc_sysctl(SB)
|
||||||
|
|
||||||
|
GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8
|
||||||
|
DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB)
|
9
internal/deps/cpu/cpu_other_arm.go
Normal file
9
internal/deps/cpu/cpu_other_arm.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !linux && arm
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func archInit() {}
|
9
internal/deps/cpu/cpu_other_arm64.go
Normal file
9
internal/deps/cpu/cpu_other_arm64.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !linux && !netbsd && !openbsd && arm64
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func doinit() {}
|
11
internal/deps/cpu/cpu_other_mips64x.go
Normal file
11
internal/deps/cpu/cpu_other_mips64x.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !linux && (mips64 || mips64le)
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func archInit() {
|
||||||
|
Initialized = true
|
||||||
|
}
|
12
internal/deps/cpu/cpu_other_ppc64x.go
Normal file
12
internal/deps/cpu/cpu_other_ppc64x.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !aix && !linux && (ppc64 || ppc64le)
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func archInit() {
|
||||||
|
PPC64.IsPOWER8 = true
|
||||||
|
Initialized = true
|
||||||
|
}
|
11
internal/deps/cpu/cpu_other_riscv64.go
Normal file
11
internal/deps/cpu/cpu_other_riscv64.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !linux && riscv64
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func archInit() {
|
||||||
|
Initialized = true
|
||||||
|
}
|
11
internal/deps/cpu/cpu_other_x86.go
Normal file
11
internal/deps/cpu/cpu_other_x86.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2024 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build 386 || amd64p32 || (amd64 && (!darwin || !gc))
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func darwinSupportsAVX512() bool {
|
||||||
|
panic("only implemented for gc && amd64 && darwin")
|
||||||
|
}
|
16
internal/deps/cpu/cpu_ppc64x.go
Normal file
16
internal/deps/cpu/cpu_ppc64x.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build ppc64 || ppc64le
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
const cacheLineSize = 128
|
||||||
|
|
||||||
|
func initOptions() {
|
||||||
|
options = []option{
|
||||||
|
{Name: "darn", Feature: &PPC64.HasDARN},
|
||||||
|
{Name: "scv", Feature: &PPC64.HasSCV},
|
||||||
|
}
|
||||||
|
}
|
20
internal/deps/cpu/cpu_riscv64.go
Normal file
20
internal/deps/cpu/cpu_riscv64.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build riscv64
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
const cacheLineSize = 64
|
||||||
|
|
||||||
|
func initOptions() {
|
||||||
|
options = []option{
|
||||||
|
{Name: "fastmisaligned", Feature: &RISCV64.HasFastMisaligned},
|
||||||
|
{Name: "c", Feature: &RISCV64.HasC},
|
||||||
|
{Name: "v", Feature: &RISCV64.HasV},
|
||||||
|
{Name: "zba", Feature: &RISCV64.HasZba},
|
||||||
|
{Name: "zbb", Feature: &RISCV64.HasZbb},
|
||||||
|
{Name: "zbs", Feature: &RISCV64.HasZbs},
|
||||||
|
}
|
||||||
|
}
|
172
internal/deps/cpu/cpu_s390x.go
Normal file
172
internal/deps/cpu/cpu_s390x.go
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
const cacheLineSize = 256
|
||||||
|
|
||||||
|
func initOptions() {
|
||||||
|
options = []option{
|
||||||
|
{Name: "zarch", Feature: &S390X.HasZARCH, Required: true},
|
||||||
|
{Name: "stfle", Feature: &S390X.HasSTFLE, Required: true},
|
||||||
|
{Name: "ldisp", Feature: &S390X.HasLDISP, Required: true},
|
||||||
|
{Name: "eimm", Feature: &S390X.HasEIMM, Required: true},
|
||||||
|
{Name: "dfp", Feature: &S390X.HasDFP},
|
||||||
|
{Name: "etf3eh", Feature: &S390X.HasETF3EH},
|
||||||
|
{Name: "msa", Feature: &S390X.HasMSA},
|
||||||
|
{Name: "aes", Feature: &S390X.HasAES},
|
||||||
|
{Name: "aescbc", Feature: &S390X.HasAESCBC},
|
||||||
|
{Name: "aesctr", Feature: &S390X.HasAESCTR},
|
||||||
|
{Name: "aesgcm", Feature: &S390X.HasAESGCM},
|
||||||
|
{Name: "ghash", Feature: &S390X.HasGHASH},
|
||||||
|
{Name: "sha1", Feature: &S390X.HasSHA1},
|
||||||
|
{Name: "sha256", Feature: &S390X.HasSHA256},
|
||||||
|
{Name: "sha3", Feature: &S390X.HasSHA3},
|
||||||
|
{Name: "sha512", Feature: &S390X.HasSHA512},
|
||||||
|
{Name: "vx", Feature: &S390X.HasVX},
|
||||||
|
{Name: "vxe", Feature: &S390X.HasVXE},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bitIsSet reports whether the bit at index is set. The bit index
|
||||||
|
// is in big endian order, so bit index 0 is the leftmost bit.
|
||||||
|
func bitIsSet(bits []uint64, index uint) bool {
|
||||||
|
return bits[index/64]&((1<<63)>>(index%64)) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// facility is a bit index for the named facility.
|
||||||
|
type facility uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// mandatory facilities
|
||||||
|
zarch facility = 1 // z architecture mode is active
|
||||||
|
stflef facility = 7 // store-facility-list-extended
|
||||||
|
ldisp facility = 18 // long-displacement
|
||||||
|
eimm facility = 21 // extended-immediate
|
||||||
|
|
||||||
|
// miscellaneous facilities
|
||||||
|
dfp facility = 42 // decimal-floating-point
|
||||||
|
etf3eh facility = 30 // extended-translation 3 enhancement
|
||||||
|
|
||||||
|
// cryptography facilities
|
||||||
|
msa facility = 17 // message-security-assist
|
||||||
|
msa3 facility = 76 // message-security-assist extension 3
|
||||||
|
msa4 facility = 77 // message-security-assist extension 4
|
||||||
|
msa5 facility = 57 // message-security-assist extension 5
|
||||||
|
msa8 facility = 146 // message-security-assist extension 8
|
||||||
|
msa9 facility = 155 // message-security-assist extension 9
|
||||||
|
|
||||||
|
// vector facilities
|
||||||
|
vx facility = 129 // vector facility
|
||||||
|
vxe facility = 135 // vector-enhancements 1
|
||||||
|
vxe2 facility = 148 // vector-enhancements 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// facilityList contains the result of an STFLE call.
|
||||||
|
// Bits are numbered in big endian order so the
|
||||||
|
// leftmost bit (the MSB) is at index 0.
|
||||||
|
type facilityList struct {
|
||||||
|
bits [4]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has reports whether the given facilities are present.
|
||||||
|
func (s *facilityList) Has(fs ...facility) bool {
|
||||||
|
if len(fs) == 0 {
|
||||||
|
panic("no facility bits provided")
|
||||||
|
}
|
||||||
|
for _, f := range fs {
|
||||||
|
if !bitIsSet(s.bits[:], uint(f)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// function is the code for the named cryptographic function.
|
||||||
|
type function uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// KM{,A,C,CTR} function codes
|
||||||
|
aes128 function = 18 // AES-128
|
||||||
|
aes192 function = 19 // AES-192
|
||||||
|
aes256 function = 20 // AES-256
|
||||||
|
|
||||||
|
// K{I,L}MD function codes
|
||||||
|
sha1 function = 1 // SHA-1
|
||||||
|
sha256 function = 2 // SHA-256
|
||||||
|
sha512 function = 3 // SHA-512
|
||||||
|
sha3_224 function = 32 // SHA3-224
|
||||||
|
sha3_256 function = 33 // SHA3-256
|
||||||
|
sha3_384 function = 34 // SHA3-384
|
||||||
|
sha3_512 function = 35 // SHA3-512
|
||||||
|
shake128 function = 36 // SHAKE-128
|
||||||
|
shake256 function = 37 // SHAKE-256
|
||||||
|
|
||||||
|
// KLMD function codes
|
||||||
|
ghash function = 65 // GHASH
|
||||||
|
)
|
||||||
|
|
||||||
|
// queryResult contains the result of a Query function
|
||||||
|
// call. Bits are numbered in big endian order so the
|
||||||
|
// leftmost bit (the MSB) is at index 0.
|
||||||
|
type queryResult struct {
|
||||||
|
bits [2]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has reports whether the given functions are present.
|
||||||
|
func (q *queryResult) Has(fns ...function) bool {
|
||||||
|
if len(fns) == 0 {
|
||||||
|
panic("no function codes provided")
|
||||||
|
}
|
||||||
|
for _, f := range fns {
|
||||||
|
if !bitIsSet(q.bits[:], uint(f)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func doinit() {
|
||||||
|
initS390Xbase()
|
||||||
|
|
||||||
|
// We need implementations of stfle, km and so on
|
||||||
|
// to detect cryptographic features.
|
||||||
|
if !haveAsmFunctions() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional cryptographic functions
|
||||||
|
if S390X.HasMSA {
|
||||||
|
aes := []function{aes128, aes192, aes256}
|
||||||
|
|
||||||
|
// cipher message
|
||||||
|
km, kmc := kmQuery(), kmcQuery()
|
||||||
|
S390X.HasAES = km.Has(aes...)
|
||||||
|
S390X.HasAESCBC = kmc.Has(aes...)
|
||||||
|
if S390X.HasSTFLE {
|
||||||
|
facilities := stfle()
|
||||||
|
if facilities.Has(msa4) {
|
||||||
|
kmctr := kmctrQuery()
|
||||||
|
S390X.HasAESCTR = kmctr.Has(aes...)
|
||||||
|
}
|
||||||
|
if facilities.Has(msa8) {
|
||||||
|
kma := kmaQuery()
|
||||||
|
S390X.HasAESGCM = kma.Has(aes...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute message digest
|
||||||
|
kimd := kimdQuery() // intermediate (no padding)
|
||||||
|
klmd := klmdQuery() // last (padding)
|
||||||
|
S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1)
|
||||||
|
S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256)
|
||||||
|
S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512)
|
||||||
|
S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist
|
||||||
|
sha3 := []function{
|
||||||
|
sha3_224, sha3_256, sha3_384, sha3_512,
|
||||||
|
shake128, shake256,
|
||||||
|
}
|
||||||
|
S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...)
|
||||||
|
}
|
||||||
|
}
|
57
internal/deps/cpu/cpu_s390x.s
Normal file
57
internal/deps/cpu/cpu_s390x.s
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build gc
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func stfle() facilityList
|
||||||
|
TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32
|
||||||
|
MOVD $ret+0(FP), R1
|
||||||
|
MOVD $3, R0 // last doubleword index to store
|
||||||
|
XC $32, (R1), (R1) // clear 4 doublewords (32 bytes)
|
||||||
|
WORD $0xb2b01000 // store facility list extended (STFLE)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func kmQuery() queryResult
|
||||||
|
TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
|
MOVD $0, R0 // set function code to 0 (KM-Query)
|
||||||
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
|
WORD $0xB92E0024 // cipher message (KM)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func kmcQuery() queryResult
|
||||||
|
TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
|
MOVD $0, R0 // set function code to 0 (KMC-Query)
|
||||||
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
|
WORD $0xB92F0024 // cipher message with chaining (KMC)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func kmctrQuery() queryResult
|
||||||
|
TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
|
MOVD $0, R0 // set function code to 0 (KMCTR-Query)
|
||||||
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
|
WORD $0xB92D4024 // cipher message with counter (KMCTR)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func kmaQuery() queryResult
|
||||||
|
TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
|
MOVD $0, R0 // set function code to 0 (KMA-Query)
|
||||||
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
|
WORD $0xb9296024 // cipher message with authentication (KMA)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func kimdQuery() queryResult
|
||||||
|
TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
|
MOVD $0, R0 // set function code to 0 (KIMD-Query)
|
||||||
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
|
WORD $0xB93E0024 // compute intermediate message digest (KIMD)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func klmdQuery() queryResult
|
||||||
|
TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
|
MOVD $0, R0 // set function code to 0 (KLMD-Query)
|
||||||
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
|
WORD $0xB93F0024 // compute last message digest (KLMD)
|
||||||
|
RET
|
75
internal/deps/cpu/cpu_s390x_test.go
Normal file
75
internal/deps/cpu/cpu_s390x_test.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/emmansun/gmsm/internal/deps/cpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
var s390xTests = []struct {
|
||||||
|
name string
|
||||||
|
feature bool
|
||||||
|
facility uint
|
||||||
|
mandatory bool
|
||||||
|
}{
|
||||||
|
{"ZARCH", cpu.S390X.HasZARCH, 1, true},
|
||||||
|
{"STFLE", cpu.S390X.HasSTFLE, 7, true},
|
||||||
|
{"LDISP", cpu.S390X.HasLDISP, 18, true},
|
||||||
|
{"EIMM", cpu.S390X.HasEIMM, 21, true},
|
||||||
|
{"DFP", cpu.S390X.HasDFP, 42, false},
|
||||||
|
{"MSA", cpu.S390X.HasMSA, 17, false},
|
||||||
|
{"VX", cpu.S390X.HasVX, 129, false},
|
||||||
|
{"VXE", cpu.S390X.HasVXE, 135, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
// bitIsSet reports whether the bit at index is set. The bit index
|
||||||
|
// is in big endian order, so bit index 0 is the leftmost bit.
|
||||||
|
func bitIsSet(bits [4]uint64, i uint) bool {
|
||||||
|
return bits[i/64]&((1<<63)>>(i%64)) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// facilityList contains the contents of location 200 on zos.
|
||||||
|
// Bits are numbered in big endian order so the
|
||||||
|
// leftmost bit (the MSB) is at index 0.
|
||||||
|
type facilityList struct {
|
||||||
|
bits [4]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestS390XVectorFacilityFeatures(t *testing.T) {
|
||||||
|
// vector-enhancements require vector facility to be enabled
|
||||||
|
if cpu.S390X.HasVXE && !cpu.S390X.HasVX {
|
||||||
|
t.Error("HasVX expected true, got false (VXE is true)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestS390XMandatoryFeatures(t *testing.T) {
|
||||||
|
for _, tc := range s390xTests {
|
||||||
|
if tc.mandatory && !tc.feature {
|
||||||
|
t.Errorf("Feature %s is mandatory but is not present", tc.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestS390XFeatures(t *testing.T) {
|
||||||
|
if runtime.GOOS != "zos" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Read available facilities from address 200.
|
||||||
|
facilitiesAddress := uintptr(200)
|
||||||
|
var facilities facilityList
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
facilities.bits[i] = *(*uint64)(unsafe.Pointer(facilitiesAddress + uintptr(8*i)))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range s390xTests {
|
||||||
|
if want := bitIsSet(facilities.bits, tc.facility); want != tc.feature {
|
||||||
|
t.Errorf("Feature %s expected %v, got %v", tc.name, want, tc.feature)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
internal/deps/cpu/cpu_wasm.go
Normal file
17
internal/deps/cpu/cpu_wasm.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build wasm
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
// We're compiling the cpu package for an unknown (software-abstracted) CPU.
|
||||||
|
// Make CacheLinePad an empty struct and hope that the usual struct alignment
|
||||||
|
// rules are good enough.
|
||||||
|
|
||||||
|
const cacheLineSize = 0
|
||||||
|
|
||||||
|
func initOptions() {}
|
||||||
|
|
||||||
|
func archInit() {}
|
162
internal/deps/cpu/cpu_x86.go
Normal file
162
internal/deps/cpu/cpu_x86.go
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build 386 || amd64 || amd64p32
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import "runtime"
|
||||||
|
|
||||||
|
const cacheLineSize = 64
|
||||||
|
|
||||||
|
func initOptions() {
|
||||||
|
options = []option{
|
||||||
|
{Name: "adx", Feature: &X86.HasADX},
|
||||||
|
{Name: "aes", Feature: &X86.HasAES},
|
||||||
|
{Name: "avx", Feature: &X86.HasAVX},
|
||||||
|
{Name: "avx2", Feature: &X86.HasAVX2},
|
||||||
|
{Name: "avx512", Feature: &X86.HasAVX512},
|
||||||
|
{Name: "avx512f", Feature: &X86.HasAVX512F},
|
||||||
|
{Name: "avx512cd", Feature: &X86.HasAVX512CD},
|
||||||
|
{Name: "avx512er", Feature: &X86.HasAVX512ER},
|
||||||
|
{Name: "avx512pf", Feature: &X86.HasAVX512PF},
|
||||||
|
{Name: "avx512vl", Feature: &X86.HasAVX512VL},
|
||||||
|
{Name: "avx512bw", Feature: &X86.HasAVX512BW},
|
||||||
|
{Name: "avx512dq", Feature: &X86.HasAVX512DQ},
|
||||||
|
{Name: "avx512ifma", Feature: &X86.HasAVX512IFMA},
|
||||||
|
{Name: "avx512vbmi", Feature: &X86.HasAVX512VBMI},
|
||||||
|
{Name: "avx512vnniw", Feature: &X86.HasAVX5124VNNIW},
|
||||||
|
{Name: "avx5124fmaps", Feature: &X86.HasAVX5124FMAPS},
|
||||||
|
{Name: "avx512vpopcntdq", Feature: &X86.HasAVX512VPOPCNTDQ},
|
||||||
|
{Name: "avx512vpclmulqdq", Feature: &X86.HasAVX512VPCLMULQDQ},
|
||||||
|
{Name: "avx512vnni", Feature: &X86.HasAVX512VNNI},
|
||||||
|
{Name: "avx512gfni", Feature: &X86.HasAVX512GFNI},
|
||||||
|
{Name: "avx512vaes", Feature: &X86.HasAVX512VAES},
|
||||||
|
{Name: "avx512vbmi2", Feature: &X86.HasAVX512VBMI2},
|
||||||
|
{Name: "avx512bitalg", Feature: &X86.HasAVX512BITALG},
|
||||||
|
{Name: "avx512bf16", Feature: &X86.HasAVX512BF16},
|
||||||
|
{Name: "amxtile", Feature: &X86.HasAMXTile},
|
||||||
|
{Name: "amxint8", Feature: &X86.HasAMXInt8},
|
||||||
|
{Name: "amxbf16", Feature: &X86.HasAMXBF16},
|
||||||
|
{Name: "bmi1", Feature: &X86.HasBMI1},
|
||||||
|
{Name: "bmi2", Feature: &X86.HasBMI2},
|
||||||
|
{Name: "cx16", Feature: &X86.HasCX16},
|
||||||
|
{Name: "erms", Feature: &X86.HasERMS},
|
||||||
|
{Name: "fma", Feature: &X86.HasFMA},
|
||||||
|
{Name: "osxsave", Feature: &X86.HasOSXSAVE},
|
||||||
|
{Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ},
|
||||||
|
{Name: "popcnt", Feature: &X86.HasPOPCNT},
|
||||||
|
{Name: "rdrand", Feature: &X86.HasRDRAND},
|
||||||
|
{Name: "rdseed", Feature: &X86.HasRDSEED},
|
||||||
|
{Name: "sse3", Feature: &X86.HasSSE3},
|
||||||
|
{Name: "sse41", Feature: &X86.HasSSE41},
|
||||||
|
{Name: "sse42", Feature: &X86.HasSSE42},
|
||||||
|
{Name: "ssse3", Feature: &X86.HasSSSE3},
|
||||||
|
{Name: "avxifma", Feature: &X86.HasAVXIFMA},
|
||||||
|
{Name: "avxvnni", Feature: &X86.HasAVXVNNI},
|
||||||
|
{Name: "avxvnniint8", Feature: &X86.HasAVXVNNIInt8},
|
||||||
|
|
||||||
|
// These capabilities should always be enabled on amd64:
|
||||||
|
{Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func archInit() {
|
||||||
|
|
||||||
|
Initialized = true
|
||||||
|
|
||||||
|
maxID, _, _, _ := cpuid(0, 0)
|
||||||
|
|
||||||
|
if maxID < 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, ecx1, edx1 := cpuid(1, 0)
|
||||||
|
X86.HasSSE2 = isSet(26, edx1)
|
||||||
|
|
||||||
|
X86.HasSSE3 = isSet(0, ecx1) // Check presence of SSE3 - bit 0 of ECX
|
||||||
|
X86.HasPCLMULQDQ = isSet(1, ecx1) // Check presence of PCLMULQDQ - bit 1 of ECX
|
||||||
|
X86.HasSSSE3 = isSet(9, ecx1) // Check presence of SSSE3 - bit 9 of ECX
|
||||||
|
X86.HasFMA = isSet(12, ecx1) // Check presence of FMA - bit 12 of ECX
|
||||||
|
X86.HasCX16 = isSet(13, ecx1) // Check presence of CX16 - bit 13 of ECX
|
||||||
|
X86.HasSSE41 = isSet(19, ecx1) // Check presence of SSE4.1 - bit 19 of ECX
|
||||||
|
X86.HasSSE42 = isSet(20, ecx1) // Check presence of SSE4.2 - bit 20 of ECX
|
||||||
|
X86.HasPOPCNT = isSet(23, ecx1) // Check presence of POPCNT - bit 23 of ECX
|
||||||
|
X86.HasAES = isSet(25, ecx1) // Check presence of AESNI - bit 25 of ECX
|
||||||
|
X86.HasOSXSAVE = isSet(27, ecx1) // Check presence of OSXSAVE - bit 27 of ECX
|
||||||
|
X86.HasRDRAND = isSet(30, ecx1) // Check presence of RDRAND - bit 30 of ECX
|
||||||
|
|
||||||
|
var osSupportsAVX, osSupportsAVX512 bool
|
||||||
|
// For XGETBV, OSXSAVE bit is required and sufficient.
|
||||||
|
if X86.HasOSXSAVE {
|
||||||
|
eax, _ := xgetbv()
|
||||||
|
// Check if XMM and YMM registers have OS support.
|
||||||
|
osSupportsAVX = isSet(1, eax) && isSet(2, eax)
|
||||||
|
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
// Darwin requires special AVX512 checks, see cpu_darwin_x86.go
|
||||||
|
osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512()
|
||||||
|
} else {
|
||||||
|
// Check if OPMASK and ZMM registers have OS support.
|
||||||
|
osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
X86.HasAVX = isSet(28, ecx1) && osSupportsAVX
|
||||||
|
|
||||||
|
if maxID < 7 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
eax7, ebx7, ecx7, edx7 := cpuid(7, 0)
|
||||||
|
X86.HasBMI1 = isSet(3, ebx7) // Check presence of BMI1 - bit 3 of EBX
|
||||||
|
X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX // Check presence of AVX2 - bit 5 of EBX
|
||||||
|
X86.HasBMI2 = isSet(8, ebx7) // Check presence of BMI2 - bit 8 of EBX
|
||||||
|
X86.HasERMS = isSet(9, ebx7)
|
||||||
|
X86.HasRDSEED = isSet(18, ebx7)
|
||||||
|
X86.HasADX = isSet(19, ebx7)
|
||||||
|
|
||||||
|
X86.HasAVX512 = isSet(16, ebx7) && osSupportsAVX512 // Because avx-512 foundation is the core required extension
|
||||||
|
if X86.HasAVX512 {
|
||||||
|
X86.HasAVX512F = true
|
||||||
|
X86.HasAVX512CD = isSet(28, ebx7) // Check presence of AVX512CD - bit 28 of EBX
|
||||||
|
X86.HasAVX512ER = isSet(27, ebx7) // Check presence of AVX512ER - bit 27 of EBX
|
||||||
|
X86.HasAVX512PF = isSet(26, ebx7) // Check presence of AVX512PF - bit 26 of EBX
|
||||||
|
X86.HasAVX512VL = isSet(31, ebx7) // Check presence of AVX512VL - bit 31 of EBX
|
||||||
|
X86.HasAVX512BW = isSet(30, ebx7) // Check presence of AVX512BW - bit 30 of EBX
|
||||||
|
X86.HasAVX512DQ = isSet(17, ebx7) // Check presence of AVX512F - bit 16 of EBX
|
||||||
|
X86.HasAVX512IFMA = isSet(21, ebx7) // Check presence of AVX512IFMA - bit 21 of EBX
|
||||||
|
X86.HasAVX512VBMI = isSet(1, ecx7) // Check presence of AVX512VBMI - bit 1 of ECX
|
||||||
|
X86.HasAVX5124VNNIW = isSet(2, edx7) // Check presence of AVX5124VNNIW - bit 2 of EDX
|
||||||
|
X86.HasAVX5124FMAPS = isSet(3, edx7) // Check presence of AVX5124FMAPS - bit 3 of EDX
|
||||||
|
X86.HasAVX512VPOPCNTDQ = isSet(14, ecx7) // Check presence of AVX512VPOPCNTDQ - bit 14 of ECX
|
||||||
|
X86.HasAVX512VPCLMULQDQ = isSet(10, ecx7) // Check presence of VPCLMULQDQ - bit 10 of ECX
|
||||||
|
X86.HasAVX512VNNI = isSet(11, ecx7) // Check presence of AVX512VNNI - bit 11 of ECX
|
||||||
|
X86.HasAVX512GFNI = isSet(8, ecx7) // Check presence of AVX512GFNI - bit 8 of ECX
|
||||||
|
X86.HasAVX512VAES = isSet(9, ecx7) // Check presence of AVX512VAES - bit 9 of ECX
|
||||||
|
X86.HasAVX512VBMI2 = isSet(6, ecx7) // Check presence of AVX512VBMI2 - bit 6 of ECX
|
||||||
|
X86.HasAVX512BITALG = isSet(12, ecx7) // Check presence of AVX512BITALG - bit 12 of ECX
|
||||||
|
}
|
||||||
|
|
||||||
|
X86.HasAMXTile = isSet(24, edx7)
|
||||||
|
X86.HasAMXInt8 = isSet(25, edx7)
|
||||||
|
X86.HasAMXBF16 = isSet(22, edx7)
|
||||||
|
|
||||||
|
// These features depend on the second level of extended features.
|
||||||
|
if eax7 >= 1 {
|
||||||
|
eax71, _, _, edx71 := cpuid(7, 1)
|
||||||
|
if X86.HasAVX512 {
|
||||||
|
X86.HasAVX512BF16 = isSet(5, eax71)
|
||||||
|
}
|
||||||
|
if X86.HasAVX {
|
||||||
|
X86.HasAVXIFMA = isSet(23, eax71) // Check presence of AVXIFMA - bit 23 of EAX
|
||||||
|
X86.HasAVXVNNI = isSet(4, eax71)
|
||||||
|
X86.HasAVXVNNIInt8 = isSet(4, edx71)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSet(bitpos uint, value uint32) bool {
|
||||||
|
return value&(1<<bitpos) != 0
|
||||||
|
}
|
37
internal/deps/cpu/cpu_x86_test.go
Normal file
37
internal/deps/cpu/cpu_x86_test.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build 386 || amd64
|
||||||
|
|
||||||
|
package cpu_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/emmansun/gmsm/internal/deps/cpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestX86ifAVX2hasAVX(t *testing.T) {
|
||||||
|
if X86.HasAVX2 && !X86.HasAVX {
|
||||||
|
t.Fatalf("HasAVX expected true when HasAVX2 is true, got false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestX86ifAVX512FhasAVX2(t *testing.T) {
|
||||||
|
if X86.HasAVX512F && !X86.HasAVX2 {
|
||||||
|
t.Fatalf("HasAVX2 expected true when HasAVX512F is true, got false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestX86ifAVX512BWhasAVX512F(t *testing.T) {
|
||||||
|
if X86.HasAVX512BW && !X86.HasAVX512F {
|
||||||
|
t.Fatalf("HasAVX512F expected true when HasAVX512BW is true, got false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestX86ifAVX512VLhasAVX512F(t *testing.T) {
|
||||||
|
if X86.HasAVX512VL && !X86.HasAVX512F {
|
||||||
|
t.Fatalf("HasAVX512F expected true when HasAVX512VL is true, got false")
|
||||||
|
}
|
||||||
|
}
|
10
internal/deps/cpu/cpu_zos.go
Normal file
10
internal/deps/cpu/cpu_zos.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func archInit() {
|
||||||
|
doinit()
|
||||||
|
Initialized = true
|
||||||
|
}
|
25
internal/deps/cpu/cpu_zos_s390x.go
Normal file
25
internal/deps/cpu/cpu_zos_s390x.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
func initS390Xbase() {
|
||||||
|
// get the facilities list
|
||||||
|
facilities := stfle()
|
||||||
|
|
||||||
|
// mandatory
|
||||||
|
S390X.HasZARCH = facilities.Has(zarch)
|
||||||
|
S390X.HasSTFLE = facilities.Has(stflef)
|
||||||
|
S390X.HasLDISP = facilities.Has(ldisp)
|
||||||
|
S390X.HasEIMM = facilities.Has(eimm)
|
||||||
|
|
||||||
|
// optional
|
||||||
|
S390X.HasETF3EH = facilities.Has(etf3eh)
|
||||||
|
S390X.HasDFP = facilities.Has(dfp)
|
||||||
|
S390X.HasMSA = facilities.Has(msa)
|
||||||
|
S390X.HasVX = facilities.Has(vx)
|
||||||
|
if S390X.HasVX {
|
||||||
|
S390X.HasVXE = facilities.Has(vxe)
|
||||||
|
}
|
||||||
|
}
|
10
internal/deps/cpu/endian_big.go
Normal file
10
internal/deps/cpu/endian_big.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build armbe || arm64be || m68k || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || shbe || sparc || sparc64
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
// IsBigEndian records whether the GOARCH's byte order is big endian.
|
||||||
|
const IsBigEndian = true
|
10
internal/deps/cpu/endian_little.go
Normal file
10
internal/deps/cpu/endian_little.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh || wasm
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
// IsBigEndian records whether the GOARCH's byte order is big endian.
|
||||||
|
const IsBigEndian = false
|
21
internal/deps/cpu/endian_test.go
Normal file
21
internal/deps/cpu/endian_test.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/emmansun/gmsm/internal/deps/cpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsBigEndian(t *testing.T) {
|
||||||
|
b := uint16(0xff00)
|
||||||
|
want := *(*byte)(unsafe.Pointer(&b)) == 0xff
|
||||||
|
if cpu.IsBigEndian != want {
|
||||||
|
t.Errorf("IsBigEndian = %t, want %t",
|
||||||
|
cpu.IsBigEndian, want)
|
||||||
|
}
|
||||||
|
}
|
71
internal/deps/cpu/hwcap_linux.go
Normal file
71
internal/deps/cpu/hwcap_linux.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_AT_HWCAP = 16
|
||||||
|
_AT_HWCAP2 = 26
|
||||||
|
|
||||||
|
procAuxv = "/proc/self/auxv"
|
||||||
|
|
||||||
|
uintSize = int(32 << (^uint(0) >> 63))
|
||||||
|
)
|
||||||
|
|
||||||
|
// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2
|
||||||
|
// These are initialized in cpu_$GOARCH.go
|
||||||
|
// and should not be changed after they are initialized.
|
||||||
|
var hwCap uint
|
||||||
|
var hwCap2 uint
|
||||||
|
|
||||||
|
func readHWCAP() error {
|
||||||
|
// For Go 1.21+, get auxv from the Go runtime.
|
||||||
|
if a := getAuxv(); len(a) > 0 {
|
||||||
|
for len(a) >= 2 {
|
||||||
|
tag, val := a[0], uint(a[1])
|
||||||
|
a = a[2:]
|
||||||
|
switch tag {
|
||||||
|
case _AT_HWCAP:
|
||||||
|
hwCap = val
|
||||||
|
case _AT_HWCAP2:
|
||||||
|
hwCap2 = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := os.ReadFile(procAuxv)
|
||||||
|
if err != nil {
|
||||||
|
// e.g. on android /proc/self/auxv is not accessible, so silently
|
||||||
|
// ignore the error and leave Initialized = false. On some
|
||||||
|
// architectures (e.g. arm64) doinit() implements a fallback
|
||||||
|
// readout and will set Initialized = true again.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bo := hostByteOrder()
|
||||||
|
for len(buf) >= 2*(uintSize/8) {
|
||||||
|
var tag, val uint
|
||||||
|
switch uintSize {
|
||||||
|
case 32:
|
||||||
|
tag = uint(bo.Uint32(buf[0:]))
|
||||||
|
val = uint(bo.Uint32(buf[4:]))
|
||||||
|
buf = buf[8:]
|
||||||
|
case 64:
|
||||||
|
tag = uint(bo.Uint64(buf[0:]))
|
||||||
|
val = uint(bo.Uint64(buf[8:]))
|
||||||
|
buf = buf[16:]
|
||||||
|
}
|
||||||
|
switch tag {
|
||||||
|
case _AT_HWCAP:
|
||||||
|
hwCap = val
|
||||||
|
case _AT_HWCAP2:
|
||||||
|
hwCap2 = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
43
internal/deps/cpu/parse.go
Normal file
43
internal/deps/cpu/parse.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
// parseRelease parses a dot-separated version number. It follows the semver
|
||||||
|
// syntax, but allows the minor and patch versions to be elided.
|
||||||
|
//
|
||||||
|
// This is a copy of the Go runtime's parseRelease from
|
||||||
|
// https://golang.org/cl/209597.
|
||||||
|
func parseRelease(rel string) (major, minor, patch int, ok bool) {
|
||||||
|
// Strip anything after a dash or plus.
|
||||||
|
for i := 0; i < len(rel); i++ {
|
||||||
|
if rel[i] == '-' || rel[i] == '+' {
|
||||||
|
rel = rel[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next := func() (int, bool) {
|
||||||
|
for i := 0; i < len(rel); i++ {
|
||||||
|
if rel[i] == '.' {
|
||||||
|
ver, err := strconv.Atoi(rel[:i])
|
||||||
|
rel = rel[i+1:]
|
||||||
|
return ver, err == nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ver, err := strconv.Atoi(rel)
|
||||||
|
rel = ""
|
||||||
|
return ver, err == nil
|
||||||
|
}
|
||||||
|
if major, ok = next(); !ok || rel == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if minor, ok = next(); !ok || rel == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
patch, ok = next()
|
||||||
|
return
|
||||||
|
}
|
38
internal/deps/cpu/parse_test.go
Normal file
38
internal/deps/cpu/parse_test.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
type parseReleaseTest struct {
|
||||||
|
in string
|
||||||
|
major, minor, patch int
|
||||||
|
}
|
||||||
|
|
||||||
|
var parseReleaseTests = []parseReleaseTest{
|
||||||
|
{"", -1, -1, -1},
|
||||||
|
{"x", -1, -1, -1},
|
||||||
|
{"5", 5, 0, 0},
|
||||||
|
{"5.12", 5, 12, 0},
|
||||||
|
{"5.12-x", 5, 12, 0},
|
||||||
|
{"5.12.1", 5, 12, 1},
|
||||||
|
{"5.12.1-x", 5, 12, 1},
|
||||||
|
{"5.12.1.0", 5, 12, 1},
|
||||||
|
{"5.20496382327982653440", -1, -1, -1},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseRelease(t *testing.T) {
|
||||||
|
for _, test := range parseReleaseTests {
|
||||||
|
major, minor, patch, ok := parseRelease(test.in)
|
||||||
|
if !ok {
|
||||||
|
major, minor, patch = -1, -1, -1
|
||||||
|
}
|
||||||
|
if test.major != major || test.minor != minor || test.patch != patch {
|
||||||
|
t.Errorf("parseRelease(%q) = (%v, %v, %v) want (%v, %v, %v)",
|
||||||
|
test.in, major, minor, patch,
|
||||||
|
test.major, test.minor, test.patch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
internal/deps/cpu/proc_cpuinfo_linux.go
Normal file
53
internal/deps/cpu/proc_cpuinfo_linux.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build linux && arm64
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func readLinuxProcCPUInfo() error {
|
||||||
|
f, err := os.Open("/proc/cpuinfo")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var buf [1 << 10]byte // enough for first CPU
|
||||||
|
n, err := io.ReadFull(f, buf[:])
|
||||||
|
if err != nil && err != io.ErrUnexpectedEOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
in := string(buf[:n])
|
||||||
|
const features = "\nFeatures : "
|
||||||
|
i := strings.Index(in, features)
|
||||||
|
if i == -1 {
|
||||||
|
return errors.New("no CPU features found")
|
||||||
|
}
|
||||||
|
in = in[i+len(features):]
|
||||||
|
if i := strings.Index(in, "\n"); i != -1 {
|
||||||
|
in = in[:i]
|
||||||
|
}
|
||||||
|
m := map[string]*bool{}
|
||||||
|
|
||||||
|
initOptions() // need it early here; it's harmless to call twice
|
||||||
|
for _, o := range options {
|
||||||
|
m[o.Name] = o.Feature
|
||||||
|
}
|
||||||
|
// The EVTSTRM field has alias "evstrm" in Go, but Linux calls it "evtstrm".
|
||||||
|
m["evtstrm"] = &ARM64.HasEVTSTRM
|
||||||
|
|
||||||
|
for _, f := range strings.Fields(in) {
|
||||||
|
if p, ok := m[f]; ok {
|
||||||
|
*p = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
16
internal/deps/cpu/runtime_auxv.go
Normal file
16
internal/deps/cpu/runtime_auxv.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
// getAuxvFn is non-nil on Go 1.21+ (via runtime_auxv_go121.go init)
|
||||||
|
// on platforms that use auxv.
|
||||||
|
var getAuxvFn func() []uintptr
|
||||||
|
|
||||||
|
func getAuxv() []uintptr {
|
||||||
|
if getAuxvFn == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return getAuxvFn()
|
||||||
|
}
|
18
internal/deps/cpu/runtime_auxv_go121.go
Normal file
18
internal/deps/cpu/runtime_auxv_go121.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build go1.21
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "unsafe" // for linkname
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname runtime_getAuxv runtime.getAuxv
|
||||||
|
func runtime_getAuxv() []uintptr
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
getAuxvFn = runtime_getAuxv
|
||||||
|
}
|
20
internal/deps/cpu/runtime_auxv_go121_test.go
Normal file
20
internal/deps/cpu/runtime_auxv_go121_test.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build go1.21
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAuxvFromRuntime(t *testing.T) {
|
||||||
|
got := getAuxv()
|
||||||
|
t.Logf("got: %v", got) // notably: we didn't panic
|
||||||
|
if runtime.GOOS == "linux" && len(got) == 0 {
|
||||||
|
t.Errorf("expected auxv on linux; got zero entries")
|
||||||
|
}
|
||||||
|
}
|
26
internal/deps/cpu/syscall_aix_gccgo.go
Normal file
26
internal/deps/cpu/syscall_aix_gccgo.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Recreate a getsystemcfg syscall handler instead of
|
||||||
|
// using the one provided by x/sys/unix to avoid having
|
||||||
|
// the dependency between them. (See golang.org/issue/32102)
|
||||||
|
// Moreover, this file will be used during the building of
|
||||||
|
// gccgo's libgo and thus must not used a CGo method.
|
||||||
|
|
||||||
|
//go:build aix && gccgo
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
//extern getsystemcfg
|
||||||
|
func gccgoGetsystemcfg(label uint32) (r uint64)
|
||||||
|
|
||||||
|
func callgetsystemcfg(label int) (r1 uintptr, e1 syscall.Errno) {
|
||||||
|
r1 = uintptr(gccgoGetsystemcfg(uint32(label)))
|
||||||
|
e1 = syscall.GetErrno()
|
||||||
|
return
|
||||||
|
}
|
35
internal/deps/cpu/syscall_aix_ppc64_gc.go
Normal file
35
internal/deps/cpu/syscall_aix_ppc64_gc.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Minimal copy of x/sys/unix so the cpu package can make a
|
||||||
|
// system call on AIX without depending on x/sys/unix.
|
||||||
|
// (See golang.org/issue/32102)
|
||||||
|
|
||||||
|
//go:build aix && ppc64 && gc
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic libc_getsystemcfg getsystemcfg "libc.a/shr_64.o"
|
||||||
|
|
||||||
|
//go:linkname libc_getsystemcfg libc_getsystemcfg
|
||||||
|
|
||||||
|
type syscallFunc uintptr
|
||||||
|
|
||||||
|
var libc_getsystemcfg syscallFunc
|
||||||
|
|
||||||
|
type errno = syscall.Errno
|
||||||
|
|
||||||
|
// Implemented in runtime/syscall_aix.go.
|
||||||
|
func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno)
|
||||||
|
func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno)
|
||||||
|
|
||||||
|
func callgetsystemcfg(label int) (r1 uintptr, e1 errno) {
|
||||||
|
r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getsystemcfg)), 1, uintptr(label), 0, 0, 0, 0, 0)
|
||||||
|
return
|
||||||
|
}
|
98
internal/deps/cpu/syscall_darwin_x86_gc.go
Normal file
98
internal/deps/cpu/syscall_darwin_x86_gc.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright 2024 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Minimal copy of x/sys/unix so the cpu package can make a
|
||||||
|
// system call on Darwin without depending on x/sys/unix.
|
||||||
|
|
||||||
|
//go:build darwin && amd64 && gc
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type _C_int int32
|
||||||
|
|
||||||
|
// adapted from unix.Uname() at x/sys/unix/syscall_darwin.go L419
|
||||||
|
func darwinOSRelease(release *[256]byte) error {
|
||||||
|
// from x/sys/unix/zerrors_openbsd_amd64.go
|
||||||
|
const (
|
||||||
|
CTL_KERN = 0x1
|
||||||
|
KERN_OSRELEASE = 0x2
|
||||||
|
)
|
||||||
|
|
||||||
|
mib := []_C_int{CTL_KERN, KERN_OSRELEASE}
|
||||||
|
n := unsafe.Sizeof(*release)
|
||||||
|
|
||||||
|
return sysctl(mib, &release[0], &n, nil, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Errno = syscall.Errno
|
||||||
|
|
||||||
|
var _zero uintptr // Single-word zero for use when we need a valid pointer to 0 bytes.
|
||||||
|
|
||||||
|
// from x/sys/unix/zsyscall_darwin_amd64.go L791-807
|
||||||
|
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
|
||||||
|
var _p0 unsafe.Pointer
|
||||||
|
if len(mib) > 0 {
|
||||||
|
_p0 = unsafe.Pointer(&mib[0])
|
||||||
|
} else {
|
||||||
|
_p0 = unsafe.Pointer(&_zero)
|
||||||
|
}
|
||||||
|
if _, _, err := syscall_syscall6(
|
||||||
|
libc_sysctl_trampoline_addr,
|
||||||
|
uintptr(_p0),
|
||||||
|
uintptr(len(mib)),
|
||||||
|
uintptr(unsafe.Pointer(old)),
|
||||||
|
uintptr(unsafe.Pointer(oldlen)),
|
||||||
|
uintptr(unsafe.Pointer(new)),
|
||||||
|
uintptr(newlen),
|
||||||
|
); err != 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var libc_sysctl_trampoline_addr uintptr
|
||||||
|
|
||||||
|
// adapted from internal/cpu/cpu_arm64_darwin.go
|
||||||
|
func darwinSysctlEnabled(name []byte) bool {
|
||||||
|
out := int32(0)
|
||||||
|
nout := unsafe.Sizeof(out)
|
||||||
|
if ret := sysctlbyname(&name[0], (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); ret != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return out > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib"
|
||||||
|
|
||||||
|
var libc_sysctlbyname_trampoline_addr uintptr
|
||||||
|
|
||||||
|
// adapted from runtime/sys_darwin.go in the pattern of sysctl() above, as defined in x/sys/unix
|
||||||
|
func sysctlbyname(name *byte, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
|
||||||
|
if _, _, err := syscall_syscall6(
|
||||||
|
libc_sysctlbyname_trampoline_addr,
|
||||||
|
uintptr(unsafe.Pointer(name)),
|
||||||
|
uintptr(unsafe.Pointer(old)),
|
||||||
|
uintptr(unsafe.Pointer(oldlen)),
|
||||||
|
uintptr(unsafe.Pointer(new)),
|
||||||
|
uintptr(newlen),
|
||||||
|
0,
|
||||||
|
); err != 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic libc_sysctlbyname sysctlbyname "/usr/lib/libSystem.B.dylib"
|
||||||
|
|
||||||
|
// Implemented in the runtime package (runtime/sys_darwin.go)
|
||||||
|
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
||||||
|
|
||||||
|
//go:linkname syscall_syscall6 syscall.syscall6
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user