/* 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() }