Files
xgcl/sm/hash.go
T
2026-05-27 23:03:00 +08:00

102 lines
2.1 KiB
Go

package sm
import (
"crypto"
"hash"
)
// Hash identifies a cryptographic hash function that is implemented in another
// package.
// I try to keep it consistent with the standard library
type Hash struct {
crypto.Hash
}
// HashFunc simply returns the value of h so that Hash implements SignerOpts.
func (h Hash) HashFunc() crypto.Hash {
return h.Hash
}
func (h Hash) String() string {
switch h {
case SM3:
return "SM3"
case SM3WithID:
return "SM3WithID"
default:
// return ""
return h.Hash.String()
}
}
var (
SM3 Hash
SM3WithID Hash
maxHash Hash
)
var SHA1 = Hash{crypto.SHA1}
var SHA256 = Hash{crypto.SHA256}
func init() {
// A hack to get the maxHash in crypto.
i := new(crypto.Hash)
*i = 1
defer func() {
_ = recover()
SM3 = Hash{Hash: *i}
SM3WithID = Hash{Hash: *i + 1}
maxHash = Hash{Hash: *i + 2}
}()
for {
(*i).Size()
*i++
}
}
// Size returns the length, in bytes, of a digest resulting from the given hash
// function. It doesn't require that the hash function in question be linked
// into the program.
func (h Hash) Size() int {
switch h {
case SM3, SM3WithID:
return 32
default:
return h.Hash.Size()
}
}
var hashes = make(map[Hash]func() hash.Hash)
// New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
if h.Hash >= SM3.Hash && h.Hash < maxHash.Hash {
f := hashes[h]
if f != nil {
return f()
}
}
return h.Hash.New()
}
// Available reports whether the given hash function is linked into the binary.
func (h Hash) Available() bool {
if h.Hash >= SM3.Hash && h.Hash < maxHash.Hash {
return true
}
return h.Hash.Available()
}
// RegisterHash registers a function that returns a new instance of the given
// hash function. This is intended to be called from the init function in
// packages that implement hash functions.
func RegisterHash(h Hash, f func() hash.Hash) {
if h.Hash >= maxHash.Hash {
panic("crypto: RegisterHash of unknown hash function")
}
// if h.Hash < SM3.Hash {
// crypto.RegisterHash(h.Hash, f)
// }
hashes[h] = f
}