Files
encryptx/sha512x/sha512x_test.go
T

253 lines
7.1 KiB
Go
Raw Normal View History

2026-09-30 15:49:12 +08:00
package sha512x_test
2025-11-03 23:40:41 +08:00
import (
2026-09-30 15:49:12 +08:00
"bytes"
"encoding/base64"
"encoding/hex"
"errors"
"os"
"path/filepath"
2025-11-03 23:40:41 +08:00
"strings"
"testing"
2026-09-30 15:49:12 +08:00
"code.yun.ink/pkg/encryptx/sha512x"
2025-11-03 23:40:41 +08:00
)
2026-09-30 15:49:12 +08:00
// 测试向量来源:FIPS 180-4 示例与 NIST 标准测试向量,并经 Python 3 hashlib 独立复算确认。
var vectors384 = []struct {
name string
input string
want string
}{
{"空串", "", "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"},
{"abc", "abc", "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"},
}
2025-11-03 23:40:41 +08:00
2026-09-30 15:49:12 +08:00
var vectors512 = []struct {
name string
input string
want string
}{
{"空串", "", "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"},
{"abc", "abc", "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"},
}
type failingReader struct{}
func (failingReader) Read([]byte) (int, error) { return 0, errors.New("模拟读取失败") }
func TestConstants(t *testing.T) {
if sha512x.Size384 != 48 || sha512x.Size512 != 64 {
t.Fatalf("Size384 = %d, Size512 = %d, 期望 48 / 64", sha512x.Size384, sha512x.Size512)
2025-11-03 23:40:41 +08:00
}
2026-09-30 15:49:12 +08:00
if sha512x.BlockSize != 128 {
t.Fatalf("BlockSize = %d, 期望 128", sha512x.BlockSize)
2025-11-03 23:40:41 +08:00
}
}
2026-09-30 15:49:12 +08:00
func TestVectors384(t *testing.T) {
for _, v := range vectors384 {
t.Run(v.name, func(t *testing.T) {
data := []byte(v.input)
sum := sha512x.Sum384(data)
if len(sum) != sha512x.Size384 {
t.Fatalf("Sum384 长度 = %d, 期望 %d", len(sum), sha512x.Size384)
}
if got := hex.EncodeToString(sum); got != v.want {
t.Errorf("Sum384 = %s, 期望 %s", got, v.want)
}
if got := sha512x.Hex384(data); got != v.want {
t.Errorf("Hex384 = %s, 期望 %s", got, v.want)
}
if want := base64.StdEncoding.EncodeToString(sum); sha512x.Base64Sum384(data) != want {
t.Errorf("Base64Sum384 = %s, 期望 %s", sha512x.Base64Sum384(data), want)
}
h := sha512x.New384()
if _, err := h.Write(data); err != nil {
t.Fatalf("Write 失败: %v", err)
}
if got := hex.EncodeToString(h.Sum(nil)); got != v.want {
t.Errorf("New384+Write = %s, 期望 %s", got, v.want)
}
})
2025-11-03 23:40:41 +08:00
}
}
2026-09-30 15:49:12 +08:00
func TestVectors512(t *testing.T) {
for _, v := range vectors512 {
t.Run(v.name, func(t *testing.T) {
data := []byte(v.input)
sum := sha512x.Sum512(data)
if len(sum) != sha512x.Size512 {
t.Fatalf("Sum512 长度 = %d, 期望 %d", len(sum), sha512x.Size512)
}
if got := hex.EncodeToString(sum); got != v.want {
t.Errorf("Sum512 = %s, 期望 %s", got, v.want)
}
if got := sha512x.Hex512(data); got != v.want {
t.Errorf("Hex512 = %s, 期望 %s", got, v.want)
}
if want := base64.StdEncoding.EncodeToString(sum); sha512x.Base64Sum512(data) != want {
t.Errorf("Base64Sum512 = %s, 期望 %s", sha512x.Base64Sum512(data), want)
}
h := sha512x.New512()
if _, err := h.Write(data); err != nil {
t.Fatalf("Write 失败: %v", err)
}
if got := hex.EncodeToString(h.Sum(nil)); got != v.want {
t.Errorf("New512+Write = %s, 期望 %s", got, v.want)
}
})
2025-11-03 23:40:41 +08:00
}
}
2026-09-30 15:49:12 +08:00
func TestDefaultAliasesMatch512(t *testing.T) {
data := []byte("encryptx alias check")
if !bytes.Equal(sha512x.Sum(data), sha512x.Sum512(data)) {
t.Error("Sum 应等价于 Sum512")
}
if sha512x.Hex(data) != sha512x.Hex512(data) {
t.Error("Hex 应等价于 Hex512")
}
if sha512x.Base64(data) != sha512x.Base64Sum512(data) {
t.Error("Base64 应等价于 Base64Sum512")
}
if h := sha512x.New(); h.Size() != sha512x.Size512 {
t.Errorf("New().Size() = %d, 期望 %d", h.Size(), sha512x.Size512)
2025-11-03 23:40:41 +08:00
}
}
2026-09-30 15:49:12 +08:00
func TestVariantsDiffer(t *testing.T) {
data := []byte("abc")
if sha512x.Hex384(data) == sha512x.Hex512(data) {
t.Error("SHA-384 与 SHA-512 的摘要不应相同")
2025-11-03 23:40:41 +08:00
}
}
2026-09-30 15:49:12 +08:00
func TestStreamingMatchesSum(t *testing.T) {
data := []byte(strings.Repeat("encryptx-sha512-", 100))
for _, tc := range []struct {
name string
h hashLike
whole []byte
}{
{"SHA-384", sha512x.New384(), sha512x.Sum384(data)},
{"SHA-512", sha512x.New512(), sha512x.Sum512(data)},
} {
t.Run(tc.name, func(t *testing.T) {
for i := 0; i < len(data); i += 11 {
end := i + 11
if end > len(data) {
end = len(data)
}
if _, err := tc.h.Write(data[i:end]); err != nil {
t.Fatalf("Write 失败: %v", err)
}
}
if sum := tc.h.Sum(nil); !bytes.Equal(sum, tc.whole) {
t.Errorf("分块写入 = %x, 期望 %x", sum, tc.whole)
}
})
}
}
// hashLike 是测试用的最小哈希接口。
type hashLike interface {
Write([]byte) (int, error)
Sum([]byte) []byte
}
func TestReaderConsistency(t *testing.T) {
const s = "encryptx 一致性检查"
sum, err := sha512x.SumReader(strings.NewReader(s))
if err != nil {
t.Fatalf("SumReader 失败: %v", err)
}
if want := sha512x.Sum512([]byte(s)); !bytes.Equal(sum, want) {
t.Errorf("SumReader = %x, 期望 %x", sum, want)
}
hexStr, err := sha512x.HexReader(strings.NewReader(s))
if err != nil {
t.Fatalf("HexReader 失败: %v", err)
}
if want := sha512x.Hex512([]byte(s)); hexStr != want {
t.Errorf("HexReader = %s, 期望 %s", hexStr, want)
}
}
func TestReaderErrors(t *testing.T) {
if _, err := sha512x.SumReader(nil); err == nil {
t.Fatal("nil 读取器应返回 error")
}
if _, err := sha512x.HexReader(nil); err == nil {
t.Fatal("nil 读取器应返回 error")
}
if _, err := sha512x.SumReader(failingReader{}); err == nil {
t.Fatal("读取失败时应返回 error")
}
}
func TestHexFile(t *testing.T) {
dir := t.TempDir()
content := []byte("文件内容 file content\n")
path := filepath.Join(dir, "sample.bin")
if err := os.WriteFile(path, content, 0o600); err != nil {
t.Fatalf("写入测试文件失败: %v", err)
}
got, err := sha512x.HexFile(path)
if err != nil {
t.Fatalf("HexFile 失败: %v", err)
}
if want := sha512x.Hex512(content); got != want {
t.Errorf("HexFile = %s, 期望 %s", got, want)
}
}
func TestHexFileErrors(t *testing.T) {
if _, err := sha512x.HexFile(filepath.Join(t.TempDir(), "不存在.bin")); err == nil {
t.Fatal("不存在的文件应返回 error")
}
if _, err := sha512x.HexFile(""); err == nil {
t.Fatal("空路径应返回 error")
}
if _, err := sha512x.HexFile(t.TempDir()); err == nil {
t.Fatal("目录路径应返回 error")
}
}
func TestLargeInput(t *testing.T) {
data := largeData(1 << 20)
want := sha512x.Hex512(data)
if got := sha512x.Hex512(data); got != want {
t.Errorf("重复计算结果不一致: %s vs %s", got, want)
}
got, err := sha512x.HexReader(bytes.NewReader(data))
if err != nil {
t.Fatalf("HexReader 失败: %v", err)
}
if got != want {
t.Errorf("HexReader = %s, 期望 %s", got, want)
}
h := sha512x.New512()
if _, err := h.Write(data[:1<<19]); err != nil {
t.Fatalf("Write 失败: %v", err)
}
if _, err := h.Write(data[1<<19:]); err != nil {
t.Fatalf("Write 失败: %v", err)
}
if got := hex.EncodeToString(h.Sum(nil)); got != want {
t.Errorf("1MiB 分块 = %s, 期望 %s", got, want)
}
}
// largeData 生成确定性的 n 字节数据。
func largeData(n int) []byte {
b := make([]byte, n)
for i := range b {
b[i] = byte(i*31 + i/7)
}
return b
}