Skip to content

Commit

Permalink
tz: Add BinaryMarshaler/BinaryUnmarshaler implementation to hash
Browse files Browse the repository at this point in the history
Closes #47.

Signed-off-by: Evgenii Baidakov <[email protected]>
  • Loading branch information
smallhive committed Feb 28, 2024
1 parent e1e4118 commit ab88ccd
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 0 deletions.
51 changes: 51 additions & 0 deletions tz/digest.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package tz

import (
"errors"
"fmt"
"hash"

"github.com/nspcc-dev/tzhash/gf127"
Expand All @@ -22,6 +24,8 @@ type digest struct {
}

// New returns a new [hash.Hash] computing the Tillich-Zémor checksum.
// The Hash also implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler
// to marshal and unmarshal the internal state of the hash.
func New() hash.Hash {
d := new(digest)
d.Reset()
Expand Down Expand Up @@ -122,3 +126,50 @@ func mulBitRightGeneric(c00, c10, c01, c11 *GF127, bit bool, tmp *GF127) {
*c11 = *tmp
}
}

// MarshalBinary implements [encoding.BinaryMarshaler].
func (d *digest) MarshalBinary() ([]byte, error) {
var (
b = make([]byte, Size)
start, end int
)

for i, a := range d.x {
state, err := a.MarshalBinary()
if err != nil {
return nil, err
}

Check warning on line 141 in tz/digest.go

View check run for this annotation

Codecov / codecov/patch

tz/digest.go#L140-L141

Added lines #L140 - L141 were not covered by tests

start = gf127.ByteSize * i
end = start + gf127.ByteSize

copy(b[start:end], state)
}

return b, nil
}

// UnmarshalBinary implements [encoding.BinaryUnmarshaler].
func (d *digest) UnmarshalBinary(b []byte) error {
if len(b) != Size {
return errors.New("tz: invalid hash state size")
}

var (
start, end int
)

for i := 0; i < 4; i++ {
var g GF127
start = gf127.ByteSize * i
end = start + gf127.ByteSize

if err := g.UnmarshalBinary(b[start:end]); err != nil {
return fmt.Errorf("gf127 unmarshal: %w", err)
}

Check warning on line 169 in tz/digest.go

View check run for this annotation

Codecov / codecov/patch

tz/digest.go#L168-L169

Added lines #L168 - L169 were not covered by tests

d.x[i] = g
}

return nil
}
56 changes: 56 additions & 0 deletions tz/digest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package tz

import (
"testing"

"github.com/stretchr/testify/require"
)

func newDigest() *digest {
d := &digest{}
d.Reset()
return d
}

func Test_digest_marshaling(t *testing.T) {
var (
d = newDigest()
marshaledState []byte
hashSum []byte
)

for i := byte(0); i < 10; i++ {
n, err := d.Write([]byte{i})
require.NoError(t, err)
require.Equal(t, 1, n)

t.Run("marshal", func(t *testing.T) {
marshaledState, err = d.MarshalBinary()

require.NoError(t, err)
require.Len(t, marshaledState, Size)

hashSum = d.Sum(nil)
require.Len(t, hashSum, Size)
})

t.Run("unmarshal", func(t *testing.T) {
unmarshalDigest := newDigest()
err = unmarshalDigest.UnmarshalBinary(marshaledState)
require.NoError(t, err)

unmarshalDigestHash := unmarshalDigest.Sum(nil)
require.Len(t, unmarshalDigestHash, Size)

require.Equal(t, hashSum, unmarshalDigestHash)
})
}

t.Run("invalid unmarshal", func(t *testing.T) {
unmarshalDigest := newDigest()
state := []byte{1, 2, 3}

err := unmarshalDigest.UnmarshalBinary(state)
require.Error(t, err)
})
}

0 comments on commit ab88ccd

Please sign in to comment.