166 lines
3.7 KiB
Go
166 lines
3.7 KiB
Go
/*
|
||
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()
|
||
}
|