From 6c75cc08718d93d8c582c021ea636d659866d78c Mon Sep 17 00:00:00 2001 From: Evgenii Date: Fri, 19 Jul 2019 18:59:41 +0300 Subject: [PATCH 1/2] Add pure Go hash implementation --- benchmark | 2 +- cmd/tzsum/main.go | 4 ++- tz/hash.go | 5 +++ tz/hash_test.go | 4 +++ tz/pure.go | 92 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 tz/pure.go diff --git a/benchmark b/benchmark index 36a75d0..93f446a 100755 --- a/benchmark +++ b/benchmark @@ -6,7 +6,7 @@ tmpfile=$1 go build ./cmd/tzsum && \ -for impl in avx avx2 avx2inline; do +for impl in avx avx2 avx2inline purego; do echo $impl implementation: /usr/bin/env time -f "time: %e seconds" ./tzsum -name $tmpfile -impl $impl echo diff --git a/cmd/tzsum/main.go b/cmd/tzsum/main.go index b62992f..5d6565e 100644 --- a/cmd/tzsum/main.go +++ b/cmd/tzsum/main.go @@ -17,7 +17,7 @@ var ( cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") memprofile = flag.String("memprofile", "", "write memory profile to `file`") filename = flag.String("name", "-", "file to use") - hashimpl = flag.String("impl", "avx2inline", "implementation to use") + hashimpl = flag.String("impl", "", "implementation to use") ) func main() { @@ -54,6 +54,8 @@ func main() { h = tz.NewWith(tz.AVX2) case "avx2inline": h = tz.NewWith(tz.AVX2Inline) + case "purego": + h = tz.NewWith(tz.PureGo) default: h = tz.New() } diff --git a/tz/hash.go b/tz/hash.go index 7396690..a7a4380 100644 --- a/tz/hash.go +++ b/tz/hash.go @@ -18,6 +18,7 @@ const ( AVX AVX2 AVX2Inline + PureGo ) func (impl Implementation) String() string { @@ -28,6 +29,8 @@ func (impl Implementation) String() string { return "AVX2" case AVX2Inline: return "AVX2Inline" + case PureGo: + return "PureGo" default: return "UNKNOWN" } @@ -41,6 +44,8 @@ func NewWith(impl Implementation) hash.Hash { return newAVX2() case AVX2Inline: return newAVX2Inline() + case PureGo: + return newPure() default: return New() } diff --git a/tz/hash_test.go b/tz/hash_test.go index 25a1df8..6574f66 100644 --- a/tz/hash_test.go +++ b/tz/hash_test.go @@ -15,6 +15,7 @@ var providers = []Implementation{ AVX, AVX2, AVX2Inline, + PureGo, } func TestNewWith(t *testing.T) { @@ -26,6 +27,9 @@ func TestNewWith(t *testing.T) { d = NewWith(AVX2Inline) require.IsType(t, (*digest3)(nil), d) + + d = NewWith(PureGo) + require.IsType(t, (*digestp)(nil), d) } var testCases = []struct { diff --git a/tz/pure.go b/tz/pure.go new file mode 100644 index 0000000..44989e3 --- /dev/null +++ b/tz/pure.go @@ -0,0 +1,92 @@ +package tz + +import ( + "github.com/nspcc-dev/tzhash/gogf127" +) + +type digestp struct { + x [4]gogf127.GF127 +} + +// New returns a new hash.Hash computing the Tillich-ZĂ©mor checksum. +func newPure() *digestp { + d := new(digestp) + d.Reset() + return d +} + +func (d *digestp) Sum(in []byte) []byte { + // Make a copy of d so that caller can keep writing and summing. + d0 := *d + h := d0.checkSum() + return append(in, h[:]...) +} + +func (d *digestp) checkSum() [hashSize]byte { + return d.byteArray() +} + +func (d *digestp) byteArray() (b [hashSize]byte) { + for i := 0; i < 4; i++ { + t := d.x[i].ByteArray() + copy(b[i*16:], t[:]) + } + return +} + +func (d *digestp) Reset() { + d.x[0] = gogf127.GF127{1, 0} + d.x[1] = gogf127.GF127{0, 0} + d.x[2] = gogf127.GF127{0, 0} + d.x[3] = gogf127.GF127{1, 0} +} + +func (d *digestp) Write(data []byte) (n int, err error) { + n = len(data) + for _, b := range data { + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x80 != 0) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x40 != 0) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x20 != 0) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x10 != 0) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x08 != 0) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x04 != 0) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x02 != 0) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x01 != 0) + } + return +} + +func (d *digestp) Size() int { + return hashSize +} + +func (d *digestp) BlockSize() int { + return hashBlockSize +} + +func mulBitRightPure(c00, c01, c10, c11 *gogf127.GF127, bit bool) { + var tmp gogf127.GF127 + if bit { + tmp = *c00 + gogf127.Mul10(c00, c00) + gogf127.Add(c00, c01, c00) + gogf127.Mul11(&tmp, &tmp) + gogf127.Add(c01, &tmp, c01) + + tmp = *c10 + gogf127.Mul10(c10, c10) + gogf127.Add(c10, c11, c10) + gogf127.Mul11(&tmp, &tmp) + gogf127.Add(c11, &tmp, c11) + } else { + tmp = *c00 + gogf127.Mul10(c00, c00) + gogf127.Add(c00, c01, c00) + *c01 = tmp + + tmp = *c10 + gogf127.Mul10(c10, c10) + gogf127.Add(c10, c11, c10) + *c11 = tmp + } +} From 7c121886504f99ded758050568deca1742cf000d Mon Sep 17 00:00:00 2001 From: Evgenii Date: Fri, 19 Jul 2019 19:04:44 +0300 Subject: [PATCH 2/2] Perform allocation outside of mulBitRightPure --- tz/pure.go | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tz/pure.go b/tz/pure.go index 44989e3..d1a5961 100644 --- a/tz/pure.go +++ b/tz/pure.go @@ -43,15 +43,16 @@ func (d *digestp) Reset() { func (d *digestp) Write(data []byte) (n int, err error) { n = len(data) + tmp := new(gogf127.GF127) for _, b := range data { - mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x80 != 0) - mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x40 != 0) - mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x20 != 0) - mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x10 != 0) - mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x08 != 0) - mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x04 != 0) - mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x02 != 0) - mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x01 != 0) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x80 != 0, tmp) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x40 != 0, tmp) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x20 != 0, tmp) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x10 != 0, tmp) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x08 != 0, tmp) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x04 != 0, tmp) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x02 != 0, tmp) + mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x01 != 0, tmp) } return } @@ -64,29 +65,28 @@ func (d *digestp) BlockSize() int { return hashBlockSize } -func mulBitRightPure(c00, c01, c10, c11 *gogf127.GF127, bit bool) { - var tmp gogf127.GF127 +func mulBitRightPure(c00, c01, c10, c11 *gogf127.GF127, bit bool, tmp *gogf127.GF127) { if bit { - tmp = *c00 + *tmp = *c00 gogf127.Mul10(c00, c00) gogf127.Add(c00, c01, c00) - gogf127.Mul11(&tmp, &tmp) - gogf127.Add(c01, &tmp, c01) + gogf127.Mul11(tmp, tmp) + gogf127.Add(c01, tmp, c01) - tmp = *c10 + *tmp = *c10 gogf127.Mul10(c10, c10) gogf127.Add(c10, c11, c10) - gogf127.Mul11(&tmp, &tmp) - gogf127.Add(c11, &tmp, c11) + gogf127.Mul11(tmp, tmp) + gogf127.Add(c11, tmp, c11) } else { - tmp = *c00 + *tmp = *c00 gogf127.Mul10(c00, c00) gogf127.Add(c00, c01, c00) - *c01 = tmp + *c01 = *tmp - tmp = *c10 + *tmp = *c10 gogf127.Mul10(c10, c10) gogf127.Add(c10, c11, c10) - *c11 = tmp + *c11 = *tmp } }