src/cypherpunks.ru/gogost/internal/gost34112012/hash.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/cypherpunks.ru/gogost/internal/gost34112012/hash_test.go | 23 ++++++++++++++++++++++- diff --git a/src/cypherpunks.ru/gogost/internal/gost34112012/hash.go b/src/cypherpunks.ru/gogost/internal/gost34112012/hash.go index 5529706c851606610d10435b93ce9cac1ff1f2cd72bf13d2dd44dcb514827cf4..8450f0302f34f7793c300431d9d609e61588f5d68f7b49a82fc84f7346c15235 100644 --- a/src/cypherpunks.ru/gogost/internal/gost34112012/hash.go +++ b/src/cypherpunks.ru/gogost/internal/gost34112012/hash.go @@ -19,11 +19,15 @@ // RFC 6986. package gost34112012 import ( + "bytes" "encoding/binary" + "errors" ) const ( BlockSize = 64 + + MarshaledName = "STREEBOG" ) var ( @@ -403,3 +407,43 @@ binary.LittleEndian.PutUint64(r[i*8:i*8+8], res64) } return r } + +func (h *Hash) MarshalBinary() (data []byte, err error) { + data = make([]byte, len(MarshaledName)+1+8+3*BlockSize+len(h.buf)) + copy(data, []byte(MarshaledName)) + idx := len(MarshaledName) + data[idx] = byte(h.size) + idx += 1 + binary.BigEndian.PutUint64(data[idx:idx+8], h.n) + idx += 8 + copy(data[idx:], h.hsh[:]) + idx += BlockSize + copy(data[idx:], h.chk[:]) + idx += BlockSize + copy(data[idx:], h.tmp[:]) + idx += BlockSize + copy(data[idx:], h.buf) + return +} + +func (h *Hash) UnmarshalBinary(data []byte) error { + if len(data) < len(MarshaledName)+1+8+3*BlockSize { + return errors.New("too short data") + } + if !bytes.HasPrefix(data, []byte(MarshaledName)) { + return errors.New("no hash name prefix") + } + idx := len(MarshaledName) + h.size = int(data[idx]) + idx += 1 + h.n = binary.BigEndian.Uint64(data[idx : idx+8]) + idx += 8 + copy(h.hsh[:], data[idx:]) + idx += BlockSize + copy(h.chk[:], data[idx:]) + idx += BlockSize + copy(h.tmp[:], data[idx:]) + idx += BlockSize + h.buf = data[idx:] + return nil +} diff --git a/src/cypherpunks.ru/gogost/internal/gost34112012/hash_test.go b/src/cypherpunks.ru/gogost/internal/gost34112012/hash_test.go index 1f5df686a2c14600c625cafbb0f49f3304ea19a7fb77c68206e1237115a0bd9c..7d827e8f0f084b954cc66523615d13f4a7f761c720ac4c4d44dab7295419b42e 100644 --- a/src/cypherpunks.ru/gogost/internal/gost34112012/hash_test.go +++ b/src/cypherpunks.ru/gogost/internal/gost34112012/hash_test.go @@ -19,6 +19,7 @@ import ( "bytes" "crypto/rand" + "encoding" "hash" "testing" "testing/quick" @@ -27,6 +28,8 @@ func TestHashInterface(t *testing.T) { h := New(64) var _ hash.Hash = h + var _ encoding.BinaryMarshaler = h + var _ encoding.BinaryUnmarshaler = h } func TestVectors(t *testing.T) { @@ -188,12 +191,30 @@ f := func(data []byte) bool { h.Reset() h.Write(data) d1 := h.Sum(nil) + h1Raw, err := h.MarshalBinary() + if err != nil { + return false + } h.Reset() for _, c := range data { h.Write([]byte{c}) } d2 := h.Sum(nil) - return bytes.Compare(d1, d2) == 0 + if bytes.Compare(d1, d2) != 0 { + return false + } + h2Raw, err := h.MarshalBinary() + if err != nil { + return false + } + if bytes.Compare(h1Raw, h2Raw) != 0 { + return false + } + hNew := New(64) + if err = hNew.UnmarshalBinary(h1Raw); err != nil { + return false + } + return bytes.Compare(hNew.Sum(nil), d1) == 0 } if err := quick.Check(f, nil); err != nil { t.Error(err)