diff --git a/.travis.yml b/.travis.yml
index 9b5bb48..1c6dc55 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,11 +2,12 @@ language: go
 sudo: false
 
 go:
-  - 1.8
-  - 1.9
   - "1.10"
+  - "1.11"
+  - "1.12"
   - master
 
 script:
   - go test -tags safe ./...
   - go test ./...
+  -
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..16f9ea8
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,8 @@
+{
+	"cSpell.enabled": true,
+	"cSpell.words": ["Println", "Yann", "cespare", "xxhash"],
+	"markdownlint.config": {
+		"MD013": false,
+		"MD046": false
+	}
+}
diff --git a/README.md b/README.md
index 23174eb..8eea28c 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,6 @@ CRC64ISOShort-8               22.2ns ± 3%
 
 Fnv64-8                       2.34µs ± 1%
 Fnv64Short-8                  74.7ns ± 8%
-#
 ```
 
 ## Usage
@@ -63,7 +62,7 @@ Fnv64Short-8                  74.7ns ± 8%
 	fmt.Println("File checksum:", h.Sum64())
 ```
 
-[<kbd>playground</kbd>](http://play.golang.org/p/rhRN3RdQyd)
+[<kbd>playground</kbd>](https://play.golang.org/p/wHKBwfu6CPV)
 
 ## TODO
 
@@ -72,4 +71,4 @@ Fnv64Short-8                  74.7ns ± 8%
 
 ## License
 
-This project is released under the Apache v2. licence. See [LICENCE](LICENCE) for more details.
+This project is released under the Apache v2. license. See [LICENSE](LICENSE) for more details.
diff --git a/benchmarks/go.mod b/benchmarks/go.mod
new file mode 100644
index 0000000..6dc5d14
--- /dev/null
+++ b/benchmarks/go.mod
@@ -0,0 +1,10 @@
+module github.com/OneOfOne/xxhash/benchmarks
+
+go 1.11
+
+require (
+	github.com/OneOfOne/xxhash v1.2.4
+	github.com/cespare/xxhash v1.1.0
+)
+
+replace github.com/OneOfOne/xxhash => ../
diff --git a/benchmarks/go.sum b/benchmarks/go.sum
new file mode 100644
index 0000000..0a63054
--- /dev/null
+++ b/benchmarks/go.sum
@@ -0,0 +1,3 @@
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
diff --git a/benchmarks/xxhash_cespare_test.go b/benchmarks/xxhash_cespare_test.go
new file mode 100644
index 0000000..20cf5dd
--- /dev/null
+++ b/benchmarks/xxhash_cespare_test.go
@@ -0,0 +1,53 @@
+package exttests
+
+import (
+	"testing"
+
+	"github.com/cespare/xxhash"
+)
+
+const inS = `Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+`
+
+var (
+	in = []byte(inS)
+)
+
+func BenchmarkXXSum64Cespare(b *testing.B) {
+	var bv uint64
+	b.Run("Func", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			bv += xxhash.Sum64(in)
+		}
+	})
+	b.Run("Struct", func(b *testing.B) {
+		h := xxhash.New()
+		for i := 0; i < b.N; i++ {
+			h.Write(in)
+			bv += h.Sum64()
+			h.Reset()
+		}
+	})
+}
+
+func BenchmarkXXSum64ShortCespare(b *testing.B) {
+	var bv uint64
+	k := []byte("Test-key-100")
+	b.Run("Func", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			bv += xxhash.Sum64(k)
+		}
+	})
+	b.Run("Struct", func(b *testing.B) {
+		h := xxhash.New()
+		for i := 0; i < b.N; i++ {
+			h.Write(k)
+			bv += h.Sum64()
+			h.Reset()
+		}
+	})
+}
diff --git a/cmd/xxhsum/.gitignore b/cmd/xxhsum/.gitignore
new file mode 100644
index 0000000..f84e573
--- /dev/null
+++ b/cmd/xxhsum/.gitignore
@@ -0,0 +1 @@
+xxhsum*
diff --git a/cmd/xxhsum/build.sh b/cmd/xxhsum/build.sh
new file mode 100644
index 0000000..6b55f6a
--- /dev/null
+++ b/cmd/xxhsum/build.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+VERSION=$1
+
+env GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o xxhsum64-${VERSION}.exe || exit 1
+env GOOS=windows GOARCH=386 CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o xxhsum32-${VERSION}.exe || exit 1
diff --git a/cmd/xxhsum/go.mod b/cmd/xxhsum/go.mod
new file mode 100644
index 0000000..ab81c85
--- /dev/null
+++ b/cmd/xxhsum/go.mod
@@ -0,0 +1,7 @@
+module github.com/OneOfOne/xxhash/cmd/xxhsum
+
+go 1.11
+
+require github.com/OneOfOne/xxhash v0.0.0-00010101000000-000000000000
+
+replace github.com/OneOfOne/xxhash => ../../
diff --git a/debian/changelog b/debian/changelog
index 8a6e5f4..07c5523 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-golang-github-oneofone-xxhash (1.2.4-2) UNRELEASED; urgency=medium
+golang-github-oneofone-xxhash (1.2.8-1) UNRELEASED; urgency=medium
 
   * Apply multi-arch hints.
     + golang-github-oneofone-xxhash-dev: Add Multi-Arch: foreign.
@@ -12,8 +12,9 @@ golang-github-oneofone-xxhash (1.2.4-2) UNRELEASED; urgency=medium
   * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository,
     Repository-Browse.
   * Update standards version to 4.5.1, no changes needed.
+  * New upstream release.
 
- -- Debian Janitor <janitor@jelmer.uk>  Thu, 29 Oct 2020 22:08:09 -0000
+ -- Debian Janitor <janitor@jelmer.uk>  Tue, 26 Apr 2022 17:36:08 -0000
 
 golang-github-oneofone-xxhash (1.2.4-1) unstable; urgency=medium
 
diff --git a/go.mod b/go.mod
index 2f33342..c6da85e 100644
--- a/go.mod
+++ b/go.mod
@@ -1 +1,3 @@
 module github.com/OneOfOne/xxhash
+
+go 1.11
diff --git a/xxhash.go b/xxhash.go
index 2387d65..af2496b 100644
--- a/xxhash.go
+++ b/xxhash.go
@@ -1,5 +1,11 @@
 package xxhash
 
+import (
+	"encoding/binary"
+	"errors"
+	"hash"
+)
+
 const (
 	prime32x1 uint32 = 2654435761
 	prime32x2 uint32 = 2246822519
@@ -22,6 +28,16 @@ const (
 	zero64x4 = 0x61c8864e7a143579
 )
 
+const (
+	magic32         = "xxh\x07"
+	magic64         = "xxh\x08"
+	marshaled32Size = len(magic32) + 4*7 + 16
+	marshaled64Size = len(magic64) + 8*6 + 32 + 1
+)
+
+func NewHash32() hash.Hash { return New32() }
+func NewHash64() hash.Hash { return New64() }
+
 // Checksum32 returns the checksum of the input data with the seed set to 0.
 func Checksum32(in []byte) uint32 {
 	return Checksum32S(in, 0)
@@ -81,6 +97,41 @@ func (xx *XXHash32) Sum(in []byte) []byte {
 	return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
 }
 
+// MarshalBinary implements the encoding.BinaryMarshaler interface.
+func (xx *XXHash32) MarshalBinary() ([]byte, error) {
+	b := make([]byte, 0, marshaled32Size)
+	b = append(b, magic32...)
+	b = appendUint32(b, xx.v1)
+	b = appendUint32(b, xx.v2)
+	b = appendUint32(b, xx.v3)
+	b = appendUint32(b, xx.v4)
+	b = appendUint32(b, xx.seed)
+	b = appendInt32(b, xx.ln)
+	b = appendInt32(b, xx.memIdx)
+	b = append(b, xx.mem[:]...)
+	return b, nil
+}
+
+// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
+func (xx *XXHash32) UnmarshalBinary(b []byte) error {
+	if len(b) < len(magic32) || string(b[:len(magic32)]) != magic32 {
+		return errors.New("xxhash: invalid hash state identifier")
+	}
+	if len(b) != marshaled32Size {
+		return errors.New("xxhash: invalid hash state size")
+	}
+	b = b[len(magic32):]
+	b, xx.v1 = consumeUint32(b)
+	b, xx.v2 = consumeUint32(b)
+	b, xx.v3 = consumeUint32(b)
+	b, xx.v4 = consumeUint32(b)
+	b, xx.seed = consumeUint32(b)
+	b, xx.ln = consumeInt32(b)
+	b, xx.memIdx = consumeInt32(b)
+	copy(xx.mem[:], b)
+	return nil
+}
+
 // Checksum64 an alias for Checksum64S(in, 0)
 func Checksum64(in []byte) uint64 {
 	return Checksum64S(in, 0)
@@ -138,6 +189,60 @@ func (xx *XXHash64) Sum(in []byte) []byte {
 	return append(in, byte(s>>56), byte(s>>48), byte(s>>40), byte(s>>32), byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
 }
 
+// MarshalBinary implements the encoding.BinaryMarshaler interface.
+func (xx *XXHash64) MarshalBinary() ([]byte, error) {
+	b := make([]byte, 0, marshaled64Size)
+	b = append(b, magic64...)
+	b = appendUint64(b, xx.v1)
+	b = appendUint64(b, xx.v2)
+	b = appendUint64(b, xx.v3)
+	b = appendUint64(b, xx.v4)
+	b = appendUint64(b, xx.seed)
+	b = appendUint64(b, xx.ln)
+	b = append(b, byte(xx.memIdx))
+	b = append(b, xx.mem[:]...)
+	return b, nil
+}
+
+// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
+func (xx *XXHash64) UnmarshalBinary(b []byte) error {
+	if len(b) < len(magic64) || string(b[:len(magic64)]) != magic64 {
+		return errors.New("xxhash: invalid hash state identifier")
+	}
+	if len(b) != marshaled64Size {
+		return errors.New("xxhash: invalid hash state size")
+	}
+	b = b[len(magic64):]
+	b, xx.v1 = consumeUint64(b)
+	b, xx.v2 = consumeUint64(b)
+	b, xx.v3 = consumeUint64(b)
+	b, xx.v4 = consumeUint64(b)
+	b, xx.seed = consumeUint64(b)
+	b, xx.ln = consumeUint64(b)
+	xx.memIdx = int8(b[0])
+	b = b[1:]
+	copy(xx.mem[:], b)
+	return nil
+}
+
+func appendInt32(b []byte, x int32) []byte { return appendUint32(b, uint32(x)) }
+
+func appendUint32(b []byte, x uint32) []byte {
+	var a [4]byte
+	binary.LittleEndian.PutUint32(a[:], x)
+	return append(b, a[:]...)
+}
+
+func appendUint64(b []byte, x uint64) []byte {
+	var a [8]byte
+	binary.LittleEndian.PutUint64(a[:], x)
+	return append(b, a[:]...)
+}
+
+func consumeInt32(b []byte) ([]byte, int32)   { bn, x := consumeUint32(b); return bn, int32(x) }
+func consumeUint32(b []byte) ([]byte, uint32) { x := u32(b); return b[4:], x }
+func consumeUint64(b []byte) ([]byte, uint64) { x := u64(b); return b[8:], x }
+
 // force the compiler to use ROTL instructions
 
 func rotl32_1(x uint32) uint32  { return (x << 1) | (x >> (32 - 1)) }
diff --git a/xxhash_cespare_test.go b/xxhash_cespare_test.go
deleted file mode 100644
index 9ab3a3b..0000000
--- a/xxhash_cespare_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// +build cespare
-
-package xxhash_test
-
-import (
-	"testing"
-
-	"github.com/cespare/xxhash"
-)
-
-func BenchmarkXXSum64Cespare(b *testing.B) {
-	var bv uint64
-	b.Run("Func", func(b *testing.B) {
-		for i := 0; i < b.N; i++ {
-			bv += xxhash.Sum64(in)
-		}
-	})
-	b.Run("Struct", func(b *testing.B) {
-		h := xxhash.New()
-		for i := 0; i < b.N; i++ {
-			h.Write(in)
-			bv += h.Sum64()
-			h.Reset()
-		}
-	})
-}
-
-func BenchmarkXXSum64ShortCespare(b *testing.B) {
-	var bv uint64
-	k := []byte("Test-key-100")
-	b.Run("Func", func(b *testing.B) {
-		for i := 0; i < b.N; i++ {
-			bv += xxhash.Sum64(k)
-		}
-	})
-	b.Run("Struct", func(b *testing.B) {
-		h := xxhash.New()
-		for i := 0; i < b.N; i++ {
-			h.Write(k)
-			bv += h.Sum64()
-			h.Reset()
-		}
-	})
-}
diff --git a/xxhash_test.go b/xxhash_test.go
index e5222df..b05ca21 100644
--- a/xxhash_test.go
+++ b/xxhash_test.go
@@ -2,12 +2,15 @@ package xxhash_test
 
 import (
 	"bytes"
+	"encoding"
 	"encoding/binary"
+	"hash"
 	"hash/adler32"
 	"hash/crc32"
 	"hash/crc64"
 	"hash/fnv"
 	"os"
+	"reflect"
 	"strconv"
 	"testing"
 
@@ -117,6 +120,59 @@ func TestSum64(t *testing.T) {
 	}
 }
 
+func TestBinaryMarshaling(t *testing.T) {
+	tests := []struct {
+		name string
+		h    func() hash.Hash
+	}{
+		{name: "xxhash32", h: xxhash.NewHash32},
+		{name: "xxhash64", h: xxhash.NewHash64},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			d := test.h()
+			d.Write([]byte("abc"))
+
+			b, err := d.(encoding.BinaryMarshaler).MarshalBinary()
+			if err != nil {
+				t.Fatal(err)
+			}
+			d = test.h()
+			d.Write([]byte("junk"))
+			if err := d.(encoding.BinaryUnmarshaler).UnmarshalBinary(b); err != nil {
+				t.Fatal(err)
+			}
+			d.Write([]byte("def"))
+
+			expected := test.h()
+			expected.Write([]byte("abcdef"))
+			if got, want := d.Sum(nil), expected.Sum(nil); !reflect.DeepEqual(got, want) {
+				t.Fatalf("after MarshalBinary+UnmarshalBinary, got 0x%x; want 0x%x", got, want)
+			}
+
+			d0 := test.h()
+			d1 := test.h()
+			for i := 0; i < 64; i++ {
+				b, err := d0.(encoding.BinaryMarshaler).MarshalBinary()
+				if err != nil {
+					t.Fatal(err)
+				}
+				d0 = test.h()
+				if err := d0.(encoding.BinaryUnmarshaler).UnmarshalBinary(b); err != nil {
+					t.Fatal(err)
+				}
+				if got, want := d0.Sum(nil), d1.Sum(nil); !reflect.DeepEqual(got, want) {
+					t.Fatalf("after %d Writes, unmarshaled hash gave sum 0x%x; want 0x%x", i, got, want)
+				}
+
+				d0.Write([]byte{'a'})
+				d1.Write([]byte{'a'})
+			}
+		})
+	}
+}
+
 func BenchmarkXXChecksum32(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		xxhash.Checksum32(in)
diff --git a/xxhash_unsafe.go b/xxhash_unsafe.go
index 10f2e84..1e2b5e8 100644
--- a/xxhash_unsafe.go
+++ b/xxhash_unsafe.go
@@ -49,18 +49,18 @@ func (xx *XXHash64) WriteString(s string) (int, error) {
 		return 0, nil
 	}
 	ss := (*reflect.StringHeader)(unsafe.Pointer(&s))
-	return xx.Write((*[maxInt32]byte)(unsafe.Pointer(ss.Data))[:len(s)])
+	return xx.Write((*[maxInt32]byte)(unsafe.Pointer(ss.Data))[:len(s):len(s)])
 }
 
+//go:nocheckptr
 func checksum64(in []byte, seed uint64) uint64 {
 	var (
 		wordsLen = len(in) >> 3
 		words    = ((*[maxInt32 / 8]uint64)(unsafe.Pointer(&in[0])))[:wordsLen:wordsLen]
 
-		h uint64 = prime64x5
-
 		v1, v2, v3, v4 = resetVs64(seed)
 
+		h uint64
 		i int
 	)
 
@@ -103,6 +103,7 @@ func checksum64(in []byte, seed uint64) uint64 {
 	return mix64(h)
 }
 
+//go:nocheckptr
 func checksum64Short(in []byte, seed uint64) uint64 {
 	var (
 		h = seed + prime64x5 + uint64(len(in))