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

166 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
Package sm3 implements the SM3 Hash algorithms
*/
package sm3
import (
"hash"
"xdx.jelly/xgcl/sm"
)
func init() {
// 注册sm.SM3、sm.SM3WithID到sm.hashs中去.
sm.RegisterHash(sm.SM3, New)
sm.RegisterHash(sm.SM3WithID, New)
}
type digest struct {
h [8]uint32
x [chunk]byte
nx int
len uint64
}
// NewDigest return a new digest type, void change `digest` to `Digest`.
// 相比标准库,增加此函数。
// 在上下文明确使用sm3的时候,可以显示用这个函数来获取sm3的digest实例,
// 而不是通过New()得到Hash接口。
func NewDigest() *digest {
d := new(digest)
d.Reset()
return d
}
// New returns a new hash.Hash computing the SM3 checksum. The Hash also
// implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to
// marshal and unmarshal the internal state of the hash.
func New() hash.Hash {
return NewDigest()
}
// Reset reset the states
func (d *digest) Reset() {
d.h[0] = init0
d.h[1] = init1
d.h[2] = init2
d.h[3] = init3
d.h[4] = init4
d.h[5] = init5
d.h[6] = init6
d.h[7] = init7
d.nx = 0
d.len = 0
}
/*
MarshalBinary和UnmarshalBinary实现了encoding.BinaryMarshaler和
encoding.BinaryMarshaler接口,可以对Sm3的中间状态转化为byte序列存储。
比如kdf函数要计算SM3(z||cnt) cnt = 1,2,3,4...,可以先update(z),保存此时
状态。
用法:
dig := New()
io.WriteString(dig, "a")
// New 返回的是hash接口, 转换为BinaryMarshaler接口
state, _ := dig.(encoding.BinaryMarshaler).MarshalBinary()
// dig do something
dig.(encoding.BinaryUnmarshaler).UnmarshalBinary(state)
补充:我们增加了NewDigest(), 返回*digest,因此可以直接用赋值保存。
d1 := NewDigest()
// ...
*d2 := *d1
*/
// MarshalBinary implements the encoding.BinaryMarshaler interface
// marshal a digest to []byte to save
// no error return.
func (d *digest) MarshalBinary() ([]byte, error) {
b := make([]byte, 0, marshaledSize)
b = append(b, magic...)
b = appendUint32(b, d.h[0])
b = appendUint32(b, d.h[1])
b = appendUint32(b, d.h[2])
b = appendUint32(b, d.h[3])
b = appendUint32(b, d.h[4])
b = appendUint32(b, d.h[5])
b = appendUint32(b, d.h[6])
b = appendUint32(b, d.h[7])
b = append(b, d.x[:]...)
b = appendUint64(b, d.len)
return b, nil
}
// UnmarshalBinary implements the encoding.BinaryMarshaler interface
// recover a digest from []byte
func (d *digest) UnmarshalBinary(b []byte) error {
if len(b) < marshaledSize || string(b[:len(magic)]) != magic {
return ErrInvalidInput
}
b = b[len(magic):]
b, d.h[0] = consumeUint32(b)
b, d.h[1] = consumeUint32(b)
b, d.h[2] = consumeUint32(b)
b, d.h[3] = consumeUint32(b)
b, d.h[4] = consumeUint32(b)
b, d.h[5] = consumeUint32(b)
b, d.h[6] = consumeUint32(b)
b, d.h[7] = consumeUint32(b)
b = b[copy(d.x[:], b):]
_, d.len = consumeUint64(b)
d.nx = int(d.len) % chunk
return nil
}
// Size returns the size of hash digest
func (d *digest) Size() int { return Size }
// BlockSize return the bytes of one block
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
// try to clear d.x
if d.nx > 0 {
n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == chunk {
block(d, d.x[:])
d.nx = 0
}
p = p[n:]
}
if len(p) >= chunk {
// n is multiple of chunk
n := len(p) &^ (chunk - 1)
block(d, p[:n])
p = p[n:]
}
if len(p) > 0 {
d.nx = copy(d.x[:], p)
}
return
}
// Sum returns the digest without change the intenal states
func (d *digest) Sum(in []byte) []byte {
// make a copy
d0 := *d
hash := d0.checkSum()
return append(in, hash[:]...)
}
// Sum returns the SM3 checksum of the data.
func Sum(data ...[]byte) [Size]byte {
var d digest
d.Reset()
for _, x := range data {
d.Write(x)
}
return d.checkSum()
}