diff options
author | Ian Lance Taylor <iant@golang.org> | 2018-01-09 01:23:08 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-01-09 01:23:08 +0000 |
commit | 1a2f01efa63036a5104f203a4789e682c0e0915d (patch) | |
tree | 373e15778dc8295354584e1f86915ae493b604ff /libgo/go/hash | |
parent | 8799df67f2dab88f9fda11739c501780a85575e2 (diff) | |
download | gcc-1a2f01efa63036a5104f203a4789e682c0e0915d.zip gcc-1a2f01efa63036a5104f203a4789e682c0e0915d.tar.gz gcc-1a2f01efa63036a5104f203a4789e682c0e0915d.tar.bz2 |
libgo: update to Go1.10beta1
Update the Go library to the 1.10beta1 release.
Requires a few changes to the compiler for modifications to the map
runtime code, and to handle some nowritebarrier cases in the runtime.
Reviewed-on: https://go-review.googlesource.com/86455
gotools/:
* Makefile.am (go_cmd_vet_files): New variable.
(go_cmd_buildid_files, go_cmd_test2json_files): New variables.
(s-zdefaultcc): Change from constants to functions.
(noinst_PROGRAMS): Add vet, buildid, and test2json.
(cgo$(EXEEXT)): Link against $(LIBGOTOOL).
(vet$(EXEEXT)): New target.
(buildid$(EXEEXT)): New target.
(test2json$(EXEEXT)): New target.
(install-exec-local): Install all $(noinst_PROGRAMS).
(uninstall-local): Uninstasll all $(noinst_PROGRAMS).
(check-go-tool): Depend on $(noinst_PROGRAMS). Copy down
objabi.go.
(check-runtime): Depend on $(noinst_PROGRAMS).
(check-cgo-test, check-carchive-test): Likewise.
(check-vet): New target.
(check): Depend on check-vet. Look at cmd_vet-testlog.
(.PHONY): Add check-vet.
* Makefile.in: Rebuild.
From-SVN: r256365
Diffstat (limited to 'libgo/go/hash')
-rw-r--r-- | libgo/go/hash/adler32/adler32.go | 50 | ||||
-rw-r--r-- | libgo/go/hash/adler32/adler32_test.go | 125 | ||||
-rw-r--r-- | libgo/go/hash/crc32/crc32.go | 71 | ||||
-rw-r--r-- | libgo/go/hash/crc32/crc32_arm64.go | 5 | ||||
-rw-r--r-- | libgo/go/hash/crc32/crc32_test.go | 150 | ||||
-rw-r--r-- | libgo/go/hash/crc64/crc64.go | 72 | ||||
-rw-r--r-- | libgo/go/hash/crc64/crc64_test.go | 154 | ||||
-rw-r--r-- | libgo/go/hash/example_test.go | 53 | ||||
-rw-r--r-- | libgo/go/hash/fnv/fnv.go | 165 | ||||
-rw-r--r-- | libgo/go/hash/fnv/fnv_test.go | 113 | ||||
-rw-r--r-- | libgo/go/hash/hash.go | 15 | ||||
-rw-r--r-- | libgo/go/hash/marshal_test.go | 107 |
12 files changed, 921 insertions, 159 deletions
diff --git a/libgo/go/hash/adler32/adler32.go b/libgo/go/hash/adler32/adler32.go index 21d6a2e..e8783e4 100644 --- a/libgo/go/hash/adler32/adler32.go +++ b/libgo/go/hash/adler32/adler32.go @@ -12,7 +12,10 @@ // significant-byte first (network) order. package adler32 -import "hash" +import ( + "errors" + "hash" +) const ( // mod is the largest prime that is less than 65536. @@ -32,8 +35,11 @@ type digest uint32 func (d *digest) Reset() { *d = 1 } -// New returns a new hash.Hash32 computing the Adler-32 checksum. -// Its Sum method will lay the value out in big-endian byte order. +// New returns a new hash.Hash32 computing the Adler-32 checksum. Its +// Sum method will lay the value out in big-endian byte order. The +// returned Hash32 also implements encoding.BinaryMarshaler and +// encoding.BinaryUnmarshaler to marshal and unmarshal the internal +// state of the hash. func New() hash.Hash32 { d := new(digest) d.Reset() @@ -44,6 +50,44 @@ func (d *digest) Size() int { return Size } func (d *digest) BlockSize() int { return 4 } +const ( + magic = "adl\x01" + marshaledSize = len(magic) + 4 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + b = appendUint32(b, uint32(*d)) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("hash/adler32: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("hash/adler32: invalid hash state size") + } + *d = digest(readUint32(b[len(magic):])) + return nil +} + +func appendUint32(b []byte, x uint32) []byte { + a := [4]byte{ + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func readUint32(b []byte) uint32 { + _ = b[3] + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + // Add p to the running checksum d. func update(d digest, p []byte) digest { s1, s2 := uint32(d&0xffff), uint32(d>>16) diff --git a/libgo/go/hash/adler32/adler32_test.go b/libgo/go/hash/adler32/adler32_test.go index 0e9c938..6bac802 100644 --- a/libgo/go/hash/adler32/adler32_test.go +++ b/libgo/go/hash/adler32/adler32_test.go @@ -5,57 +5,60 @@ package adler32 import ( + "encoding" + "io" "strings" "testing" ) var golden = []struct { - out uint32 - in string + out uint32 + in string + halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal }{ - {0x00000001, ""}, - {0x00620062, "a"}, - {0x012600c4, "ab"}, - {0x024d0127, "abc"}, - {0x03d8018b, "abcd"}, - {0x05c801f0, "abcde"}, - {0x081e0256, "abcdef"}, - {0x0adb02bd, "abcdefg"}, - {0x0e000325, "abcdefgh"}, - {0x118e038e, "abcdefghi"}, - {0x158603f8, "abcdefghij"}, - {0x3f090f02, "Discard medicine more than two years old."}, - {0x46d81477, "He who has a shady past knows that nice guys finish last."}, - {0x40ee0ee1, "I wouldn't marry him with a ten foot pole."}, - {0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {0x5b2e1480, "The days of the digital watch are numbered. -Tom Stoppard"}, - {0x8c3c09ea, "Nepal premier won't resign."}, - {0x45ac18fd, "For every action there is an equal and opposite government program."}, - {0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine."}, - {0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {0x61b507df, "size: a.out: bad magic"}, - {0xb8631171, "The major problem is with sendmail. -Mark Horton"}, - {0x8b5e1904, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {0x7cc6102b, "If the enemy is within range, then so are you."}, - {0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams."}, - {0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway."}, - {0xb55b0b09, "C is as portable as Stonehedge!!"}, - {0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {0x2e5d1316, "How can you write a big system without C++? -Paul Glick"}, - {0xd0201df6, "'Invariant assertions' is the most elegant programming technique! -Tom Szymanski"}, - {0x211297c8, strings.Repeat("\xff", 5548) + "8"}, - {0xbaa198c8, strings.Repeat("\xff", 5549) + "9"}, - {0x553499be, strings.Repeat("\xff", 5550) + "0"}, - {0xf0c19abe, strings.Repeat("\xff", 5551) + "1"}, - {0x8d5c9bbe, strings.Repeat("\xff", 5552) + "2"}, - {0x2af69cbe, strings.Repeat("\xff", 5553) + "3"}, - {0xc9809dbe, strings.Repeat("\xff", 5554) + "4"}, - {0x69189ebe, strings.Repeat("\xff", 5555) + "5"}, - {0x86af0001, strings.Repeat("\x00", 1e5)}, - {0x79660b4d, strings.Repeat("a", 1e5)}, - {0x110588ee, strings.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1e4)}, + {0x00000001, "", "adl\x01\x00\x00\x00\x01"}, + {0x00620062, "a", "adl\x01\x00\x00\x00\x01"}, + {0x012600c4, "ab", "adl\x01\x00b\x00b"}, + {0x024d0127, "abc", "adl\x01\x00b\x00b"}, + {0x03d8018b, "abcd", "adl\x01\x01&\x00\xc4"}, + {0x05c801f0, "abcde", "adl\x01\x01&\x00\xc4"}, + {0x081e0256, "abcdef", "adl\x01\x02M\x01'"}, + {0x0adb02bd, "abcdefg", "adl\x01\x02M\x01'"}, + {0x0e000325, "abcdefgh", "adl\x01\x03\xd8\x01\x8b"}, + {0x118e038e, "abcdefghi", "adl\x01\x03\xd8\x01\x8b"}, + {0x158603f8, "abcdefghij", "adl\x01\x05\xc8\x01\xf0"}, + {0x3f090f02, "Discard medicine more than two years old.", "adl\x01NU\a\x87"}, + {0x46d81477, "He who has a shady past knows that nice guys finish last.", "adl\x01\x89\x8e\t\xe9"}, + {0x40ee0ee1, "I wouldn't marry him with a ten foot pole.", "adl\x01R\t\ag"}, + {0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "adl\x01\u007f\xbb\t\x10"}, + {0x5b2e1480, "The days of the digital watch are numbered. -Tom Stoppard", "adl\x01\x99:\n~"}, + {0x8c3c09ea, "Nepal premier won't resign.", "adl\x01\"\x05\x05\x05"}, + {0x45ac18fd, "For every action there is an equal and opposite government program.", "adl\x01\xcc\xfa\f\x00"}, + {0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine.", "adl\x01\x93\xa9\n\b"}, + {0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "adl\x01e\xf5\x10\x14"}, + {0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "adl\x01\xee\x00\f\xb2"}, + {0x61b507df, "size: a.out: bad magic", "adl\x01\x1a\xfc\x04\x1d"}, + {0xb8631171, "The major problem is with sendmail. -Mark Horton", "adl\x01mi\b\xdc"}, + {0x8b5e1904, "Give me a rock, paper and scissors and I will move the world. CCFestoon", "adl\x01\xe3\n\f\x9f"}, + {0x7cc6102b, "If the enemy is within range, then so are you.", "adl\x01_\xe0\b\x1e"}, + {0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams.", "adl\x01ۘ\f\x87"}, + {0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway.", "adl\x01\xcc}\v\x83"}, + {0xb55b0b09, "C is as portable as Stonehedge!!", "adl\x01,^\x05\xad"}, + {0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "adl\x01M\xd1\x0e\xc8"}, + {0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "adl\x01#\xd8\x17\xd7"}, + {0x2e5d1316, "How can you write a big system without C++? -Paul Glick", "adl\x01\x8fU\n\x0f"}, + {0xd0201df6, "'Invariant assertions' is the most elegant programming technique! -Tom Szymanski", "adl\x01/\x98\x0e\xc4"}, + {0x211297c8, strings.Repeat("\xff", 5548) + "8", "adl\x01\x9a\xa6\xcb\xc1"}, + {0xbaa198c8, strings.Repeat("\xff", 5549) + "9", "adl\x01gu\xcc\xc0"}, + {0x553499be, strings.Repeat("\xff", 5550) + "0", "adl\x01gu\xcc\xc0"}, + {0xf0c19abe, strings.Repeat("\xff", 5551) + "1", "adl\x015CͿ"}, + {0x8d5c9bbe, strings.Repeat("\xff", 5552) + "2", "adl\x015CͿ"}, + {0x2af69cbe, strings.Repeat("\xff", 5553) + "3", "adl\x01\x04\x10ξ"}, + {0xc9809dbe, strings.Repeat("\xff", 5554) + "4", "adl\x01\x04\x10ξ"}, + {0x69189ebe, strings.Repeat("\xff", 5555) + "5", "adl\x01\xd3\xcdϽ"}, + {0x86af0001, strings.Repeat("\x00", 1e5), "adl\x01\xc3P\x00\x01"}, + {0x79660b4d, strings.Repeat("a", 1e5), "adl\x01\x81k\x05\xa7"}, + {0x110588ee, strings.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1e4), "adl\x01e\xd2\xc4p"}, } // checksum is a slow but simple implementation of the Adler-32 checksum. @@ -87,6 +90,38 @@ func TestGolden(t *testing.T) { } } +func TestGoldenMarshal(t *testing.T) { + for _, g := range golden { + h := New() + h2 := New() + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfState { + t.Errorf("checksum(%q) state = %q, want %q", g.in, state, g.halfState) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if h.Sum32() != h2.Sum32() { + t.Errorf("checksum(%q) = 0x%x != marshaled (0x%x)", g.in, h.Sum32(), h2.Sum32()) + } + } +} + func BenchmarkAdler32KB(b *testing.B) { b.SetBytes(1024) data := make([]byte, 1024) diff --git a/libgo/go/hash/crc32/crc32.go b/libgo/go/hash/crc32/crc32.go index 8aa91b1..1912caa 100644 --- a/libgo/go/hash/crc32/crc32.go +++ b/libgo/go/hash/crc32/crc32.go @@ -13,6 +13,7 @@ package crc32 import ( + "errors" "hash" "sync" ) @@ -138,9 +139,11 @@ type digest struct { tab *Table } -// New creates a new hash.Hash32 computing the CRC-32 checksum -// using the polynomial represented by the Table. -// Its Sum method will lay the value out in big-endian byte order. +// New creates a new hash.Hash32 computing the CRC-32 checksum using the +// polynomial represented by the Table. Its Sum method will lay the +// value out in big-endian byte order. The returned Hash32 also +// implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to +// marshal and unmarshal the internal state of the hash. func New(tab *Table) hash.Hash32 { if tab == IEEETable { ieeeOnce.Do(ieeeInit) @@ -148,9 +151,11 @@ func New(tab *Table) hash.Hash32 { return &digest{0, tab} } -// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum -// using the IEEE polynomial. -// Its Sum method will lay the value out in big-endian byte order. +// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum using +// the IEEE polynomial. Its Sum method will lay the value out in +// big-endian byte order. The returned Hash32 also implements +// encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to marshal +// and unmarshal the internal state of the hash. func NewIEEE() hash.Hash32 { return New(IEEETable) } func (d *digest) Size() int { return Size } @@ -159,6 +164,48 @@ func (d *digest) BlockSize() int { return 1 } func (d *digest) Reset() { d.crc = 0 } +const ( + magic = "crc\x01" + marshaledSize = len(magic) + 4 + 4 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + b = appendUint32(b, tableSum(d.tab)) + b = appendUint32(b, d.crc) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("hash/crc32: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("hash/crc32: invalid hash state size") + } + if tableSum(d.tab) != readUint32(b[4:]) { + return errors.New("hash/crc32: tables do not match") + } + d.crc = readUint32(b[8:]) + return nil +} + +func appendUint32(b []byte, x uint32) []byte { + a := [4]byte{ + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func readUint32(b []byte) uint32 { + _ = b[3] + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + // Update returns the result of adding the bytes in p to the crc. func Update(crc uint32, tab *Table, p []byte) uint32 { switch tab { @@ -205,3 +252,15 @@ func ChecksumIEEE(data []byte) uint32 { ieeeOnce.Do(ieeeInit) return updateIEEE(0, data) } + +// tableSum returns the IEEE checksum of table t. +func tableSum(t *Table) uint32 { + var a [1024]byte + b := a[:0] + if t != nil { + for _, x := range t { + b = appendUint32(b, x) + } + } + return ChecksumIEEE(b) +} diff --git a/libgo/go/hash/crc32/crc32_arm64.go b/libgo/go/hash/crc32/crc32_arm64.go index 4c5cad1..0d813b4 100644 --- a/libgo/go/hash/crc32/crc32_arm64.go +++ b/libgo/go/hash/crc32/crc32_arm64.go @@ -10,11 +10,12 @@ package crc32 -func supportsCRC32() bool +import "internal/cpu" + func castagnoliUpdate(crc uint32, p []byte) uint32 func ieeeUpdate(crc uint32, p []byte) uint32 -var hasCRC32 = supportsCRC32() +var hasCRC32 = cpu.ARM64.HasCRC32 func archAvailableCastagnoli() bool { return hasCRC32 diff --git a/libgo/go/hash/crc32/crc32_test.go b/libgo/go/hash/crc32/crc32_test.go index 0492f46..4bdafaf 100644 --- a/libgo/go/hash/crc32/crc32_test.go +++ b/libgo/go/hash/crc32/crc32_test.go @@ -5,49 +5,53 @@ package crc32 import ( + "encoding" "fmt" "hash" + "io" "math/rand" "testing" ) type test struct { - ieee, castagnoli uint32 - in string + ieee, castagnoli uint32 + in string + halfStateIEEE string // IEEE marshaled hash state after first half of in written, used by TestGoldenMarshal + halfStateCastagnoli string // Castagnoli marshaled hash state after first half of in written, used by TestGoldenMarshal } var golden = []test{ - {0x0, 0x0, ""}, - {0xe8b7be43, 0xc1d04330, "a"}, - {0x9e83486d, 0xe2a22936, "ab"}, - {0x352441c2, 0x364b3fb7, "abc"}, - {0xed82cd11, 0x92c80a31, "abcd"}, - {0x8587d865, 0xc450d697, "abcde"}, - {0x4b8e39ef, 0x53bceff1, "abcdef"}, - {0x312a6aa6, 0xe627f441, "abcdefg"}, - {0xaeef2a50, 0xa9421b7, "abcdefgh"}, - {0x8da988af, 0x2ddc99fc, "abcdefghi"}, - {0x3981703a, 0xe6599437, "abcdefghij"}, - {0x6b9cdfe7, 0xb2cc01fe, "Discard medicine more than two years old."}, - {0xc90ef73f, 0xe28207f, "He who has a shady past knows that nice guys finish last."}, - {0xb902341f, 0xbe93f964, "I wouldn't marry him with a ten foot pole."}, - {0x42080e8, 0x9e3be0c3, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {0x154c6d11, 0xf505ef04, "The days of the digital watch are numbered. -Tom Stoppard"}, - {0x4c418325, 0x85d3dc82, "Nepal premier won't resign."}, - {0x33955150, 0xc5142380, "For every action there is an equal and opposite government program."}, - {0x26216a4b, 0x75eb77dd, "His money is twice tainted: 'taint yours and 'taint mine."}, - {0x1abbe45e, 0x91ebe9f7, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {0xc89a94f7, 0xf0b1168e, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {0xab3abe14, 0x572b74e2, "size: a.out: bad magic"}, - {0xbab102b6, 0x8a58a6d5, "The major problem is with sendmail. -Mark Horton"}, - {0x999149d7, 0x9c426c50, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {0x6d52a33c, 0x735400a4, "If the enemy is within range, then so are you."}, - {0x90631e8d, 0xbec49c95, "It's well we cannot hear the screams/That we create in others' dreams."}, - {0x78309130, 0xa95a2079, "You remind me of a TV show, but that's all right: I watch it anyway."}, - {0x7d0a377f, 0xde2e65c5, "C is as portable as Stonehedge!!"}, - {0x8c79fd79, 0x297a88ed, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {0xa20b7167, 0x66ed1d8b, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {0x8e0bb443, 0xdcded527, "How can you write a big system without C++? -Paul Glick"}, + {0x0, 0x0, "", "crc\x01ʇ\x91M\x00\x00\x00\x00", "crc\x01wB\x84\x81\x00\x00\x00\x00"}, + {0xe8b7be43, 0xc1d04330, "a", "crc\x01ʇ\x91M\x00\x00\x00\x00", "crc\x01wB\x84\x81\x00\x00\x00\x00"}, + {0x9e83486d, 0xe2a22936, "ab", "crc\x01ʇ\x91M跾C", "crc\x01wB\x84\x81\xc1\xd0C0"}, + {0x352441c2, 0x364b3fb7, "abc", "crc\x01ʇ\x91M跾C", "crc\x01wB\x84\x81\xc1\xd0C0"}, + {0xed82cd11, 0x92c80a31, "abcd", "crc\x01ʇ\x91M\x9e\x83Hm", "crc\x01wB\x84\x81\xe2\xa2)6"}, + {0x8587d865, 0xc450d697, "abcde", "crc\x01ʇ\x91M\x9e\x83Hm", "crc\x01wB\x84\x81\xe2\xa2)6"}, + {0x4b8e39ef, 0x53bceff1, "abcdef", "crc\x01ʇ\x91M5$A\xc2", "crc\x01wB\x84\x816K?\xb7"}, + {0x312a6aa6, 0xe627f441, "abcdefg", "crc\x01ʇ\x91M5$A\xc2", "crc\x01wB\x84\x816K?\xb7"}, + {0xaeef2a50, 0xa9421b7, "abcdefgh", "crc\x01ʇ\x91M\xed\x82\xcd\x11", "crc\x01wB\x84\x81\x92\xc8\n1"}, + {0x8da988af, 0x2ddc99fc, "abcdefghi", "crc\x01ʇ\x91M\xed\x82\xcd\x11", "crc\x01wB\x84\x81\x92\xc8\n1"}, + {0x3981703a, 0xe6599437, "abcdefghij", "crc\x01ʇ\x91M\x85\x87\xd8e", "crc\x01wB\x84\x81\xc4P֗"}, + {0x6b9cdfe7, 0xb2cc01fe, "Discard medicine more than two years old.", "crc\x01ʇ\x91M\xfd\xe5\xc2J", "crc\x01wB\x84\x81S\"(\xe0"}, + {0xc90ef73f, 0xe28207f, "He who has a shady past knows that nice guys finish last.", "crc\x01ʇ\x91M\x01Nj+", "crc\x01wB\x84\x81'\xdaR\x15"}, + {0xb902341f, 0xbe93f964, "I wouldn't marry him with a ten foot pole.", "crc\x01ʇ\x91M\x9d\x13\xce\x10", "crc\x01wB\x84\x81\xc3\xed\xabG"}, + {0x42080e8, 0x9e3be0c3, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "crc\x01ʇ\x91M-\xed\xf7\x94", "crc\x01wB\x84\x81\xce\xceb\x81"}, + {0x154c6d11, 0xf505ef04, "The days of the digital watch are numbered. -Tom Stoppard", "crc\x01ʇ\x91MOa\xa5\r", "crc\x01wB\x84\x81\xd3s\x9dP"}, + {0x4c418325, 0x85d3dc82, "Nepal premier won't resign.", "crc\x01ʇ\x91M\xa8S9\x85", "crc\x01wB\x84\x81{\x90\x8a\x14"}, + {0x33955150, 0xc5142380, "For every action there is an equal and opposite government program.", "crc\x01ʇ\x91Ma\xe9>\x86", "crc\x01wB\x84\x81\xaa@\xc4\x1c"}, + {0x26216a4b, 0x75eb77dd, "His money is twice tainted: 'taint yours and 'taint mine.", "crc\x01ʇ\x91M\\\x1an\x88", "crc\x01wB\x84\x81W\a8Z"}, + {0x1abbe45e, 0x91ebe9f7, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "crc\x01ʇ\x91M\xb7\xf5\xf2\xca", "crc\x01wB\x84\x81\xc4o\x9d\x85"}, + {0xc89a94f7, 0xf0b1168e, "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "crc\x01ʇ\x91M\x84g1\xe8", "crc\x01wB\x84\x81#\x98\f\xab"}, + {0xab3abe14, 0x572b74e2, "size: a.out: bad magic", "crc\x01ʇ\x91M\x8a\x0f\xad\b", "crc\x01wB\x84\x81\x80\xc9n\xd8"}, + {0xbab102b6, 0x8a58a6d5, "The major problem is with sendmail. -Mark Horton", "crc\x01ʇ\x91M\a\xf0\xb3\x15", "crc\x01wB\x84\x81liS\xcc"}, + {0x999149d7, 0x9c426c50, "Give me a rock, paper and scissors and I will move the world. CCFestoon", "crc\x01ʇ\x91M\x0fa\xbc.", "crc\x01wB\x84\x81\xdb͏C"}, + {0x6d52a33c, 0x735400a4, "If the enemy is within range, then so are you.", "crc\x01ʇ\x91My\x1b\x99\xf8", "crc\x01wB\x84\x81\xaaB\x037"}, + {0x90631e8d, 0xbec49c95, "It's well we cannot hear the screams/That we create in others' dreams.", "crc\x01ʇ\x91M\bqfY", "crc\x01wB\x84\x81\x16y\xa1\xd2"}, + {0x78309130, 0xa95a2079, "You remind me of a TV show, but that's all right: I watch it anyway.", "crc\x01ʇ\x91M\xbdO,\xc2", "crc\x01wB\x84\x81f&\xc5\xe4"}, + {0x7d0a377f, 0xde2e65c5, "C is as portable as Stonehedge!!", "crc\x01ʇ\x91M\xf7\xd6\x00\xd5", "crc\x01wB\x84\x81de\\\xf8"}, + {0x8c79fd79, 0x297a88ed, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "crc\x01ʇ\x91Ml+\xb8\xa7", "crc\x01wB\x84\x81\xbf\xd6S\xdd"}, + {0xa20b7167, 0x66ed1d8b, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "crc\x01ʇ\x91M<lR[", "crc\x01wB\x84\x81{\xaco\xb1"}, + {0x8e0bb443, 0xdcded527, "How can you write a big system without C++? -Paul Glick", "crc\x01ʇ\x91M\x0e\x88\x89\xed", "crc\x01wB\x84\x813\xd7C\u007f"}, } // testGoldenIEEE verifies that the given function returns @@ -105,6 +109,86 @@ func TestSimple(t *testing.T) { }) } +func TestGoldenMarshal(t *testing.T) { + t.Run("IEEE", func(t *testing.T) { + for _, g := range golden { + h := New(IEEETable) + h2 := New(IEEETable) + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfStateIEEE { + t.Errorf("IEEE(%q) state = %q, want %q", g.in, state, g.halfStateIEEE) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if h.Sum32() != h2.Sum32() { + t.Errorf("IEEE(%s) = 0x%x != marshaled 0x%x", g.in, h.Sum32(), h2.Sum32()) + } + } + }) + t.Run("Castagnoli", func(t *testing.T) { + table := MakeTable(Castagnoli) + for _, g := range golden { + h := New(table) + h2 := New(table) + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfStateCastagnoli { + t.Errorf("Castagnoli(%q) state = %q, want %q", g.in, state, g.halfStateCastagnoli) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if h.Sum32() != h2.Sum32() { + t.Errorf("Castagnoli(%s) = 0x%x != marshaled 0x%x", g.in, h.Sum32(), h2.Sum32()) + } + } + }) +} + +func TestMarshalTableMismatch(t *testing.T) { + h1 := New(IEEETable) + h2 := New(MakeTable(Castagnoli)) + + state1, err := h1.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state1); err == nil { + t.Errorf("no error when one was expected") + } +} + // TestSimple tests the slicing-by-8 algorithm. func TestSlicing(t *testing.T) { tab := slicingMakeTable(IEEE) diff --git a/libgo/go/hash/crc64/crc64.go b/libgo/go/hash/crc64/crc64.go index e939c2a..3b24c24 100644 --- a/libgo/go/hash/crc64/crc64.go +++ b/libgo/go/hash/crc64/crc64.go @@ -7,7 +7,10 @@ // information. package crc64 -import "hash" +import ( + "errors" + "hash" +) // The size of a CRC-64 checksum in bytes. const Size = 8 @@ -77,9 +80,11 @@ type digest struct { tab *Table } -// New creates a new hash.Hash64 computing the CRC-64 checksum -// using the polynomial represented by the Table. -// Its Sum method will lay the value out in big-endian byte order. +// New creates a new hash.Hash64 computing the CRC-64 checksum using the +// polynomial represented by the Table. Its Sum method will lay the +// value out in big-endian byte order. The returned Hash64 also +// implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to +// marshal and unmarshal the internal state of the hash. func New(tab *Table) hash.Hash64 { return &digest{0, tab} } func (d *digest) Size() int { return Size } @@ -88,6 +93,53 @@ func (d *digest) BlockSize() int { return 1 } func (d *digest) Reset() { d.crc = 0 } +const ( + magic = "crc\x02" + marshaledSize = len(magic) + 8 + 8 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + b = appendUint64(b, tableSum(d.tab)) + b = appendUint64(b, d.crc) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("hash/crc64: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("hash/crc64: invalid hash state size") + } + if tableSum(d.tab) != readUint64(b[4:]) { + return errors.New("hash/crc64: tables do not match") + } + d.crc = readUint64(b[12:]) + return nil +} + +func appendUint64(b []byte, x uint64) []byte { + a := [8]byte{ + byte(x >> 56), + byte(x >> 48), + byte(x >> 40), + byte(x >> 32), + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func readUint64(b []byte) uint64 { + _ = b[7] + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} + func update(crc uint64, tab *Table, p []byte) uint64 { crc = ^crc // Table comparison is somewhat expensive, so avoid it for small sizes @@ -145,3 +197,15 @@ func (d *digest) Sum(in []byte) []byte { // Checksum returns the CRC-64 checksum of data // using the polynomial represented by the Table. func Checksum(data []byte, tab *Table) uint64 { return update(0, tab, data) } + +// tableSum returns the ISO checksum of table t. +func tableSum(t *Table) uint64 { + var a [2048]byte + b := a[:0] + if t != nil { + for _, x := range t { + b = appendUint64(b, x) + } + } + return Checksum(b, MakeTable(ISO)) +} diff --git a/libgo/go/hash/crc64/crc64_test.go b/libgo/go/hash/crc64/crc64_test.go index 480b150..9db05b0 100644 --- a/libgo/go/hash/crc64/crc64_test.go +++ b/libgo/go/hash/crc64/crc64_test.go @@ -5,49 +5,52 @@ package crc64 import ( + "encoding" "io" "testing" ) type test struct { - outISO uint64 - outECMA uint64 - in string + outISO uint64 + outECMA uint64 + in string + halfStateISO string // ISO marshaled hash state after first half of in written, used by TestGoldenMarshal + halfStateECMA string // ECMA marshaled hash state after first half of in written, used by TestGoldenMarshal } var golden = []test{ - {0x0, 0x0, ""}, - {0x3420000000000000, 0x330284772e652b05, "a"}, - {0x36c4200000000000, 0xbc6573200e84b046, "ab"}, - {0x3776c42000000000, 0x2cd8094a1a277627, "abc"}, - {0x336776c420000000, 0x3c9d28596e5960ba, "abcd"}, - {0x32d36776c4200000, 0x40bdf58fb0895f2, "abcde"}, - {0x3002d36776c42000, 0xd08e9f8545a700f4, "abcdef"}, - {0x31b002d36776c420, 0xec20a3a8cc710e66, "abcdefg"}, - {0xe21b002d36776c4, 0x67b4f30a647a0c59, "abcdefgh"}, - {0x8b6e21b002d36776, 0x9966f6c89d56ef8e, "abcdefghi"}, - {0x7f5b6e21b002d367, 0x32093a2ecd5773f4, "abcdefghij"}, - {0x8ec0e7c835bf9cdf, 0x8a0825223ea6d221, "Discard medicine more than two years old."}, - {0xc7db1759e2be5ab4, 0x8562c0ac2ab9a00d, "He who has a shady past knows that nice guys finish last."}, - {0xfbf9d9603a6fa020, 0x3ee2a39c083f38b4, "I wouldn't marry him with a ten foot pole."}, - {0xeafc4211a6daa0ef, 0x1f603830353e518a, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {0x3e05b21c7a4dc4da, 0x2fd681d7b2421fd, "The days of the digital watch are numbered. -Tom Stoppard"}, - {0x5255866ad6ef28a6, 0x790ef2b16a745a41, "Nepal premier won't resign."}, - {0x8a79895be1e9c361, 0x3ef8f06daccdcddf, "For every action there is an equal and opposite government program."}, - {0x8878963a649d4916, 0x49e41b2660b106d, "His money is twice tainted: 'taint yours and 'taint mine."}, - {0xa7b9d53ea87eb82f, 0x561cc0cfa235ac68, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {0xdb6805c0966a2f9c, 0xd4fe9ef082e69f59, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {0xf3553c65dacdadd2, 0xe3b5e46cd8d63a4d, "size: a.out: bad magic"}, - {0x9d5e034087a676b9, 0x865aaf6b94f2a051, "The major problem is with sendmail. -Mark Horton"}, - {0xa6db2d7f8da96417, 0x7eca10d2f8136eb4, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {0x325e00cd2fe819f9, 0xd7dd118c98e98727, "If the enemy is within range, then so are you."}, - {0x88c6600ce58ae4c6, 0x70fb33c119c29318, "It's well we cannot hear the screams/That we create in others' dreams."}, - {0x28c4a3f3b769e078, 0x57c891e39a97d9b7, "You remind me of a TV show, but that's all right: I watch it anyway."}, - {0xa698a34c9d9f1dca, 0xa1f46ba20ad06eb7, "C is as portable as Stonehedge!!"}, - {0xf6c1e2a8c26c5cfc, 0x7ad25fafa1710407, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {0xd402559dfe9b70c, 0x73cef1666185c13f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {0xdb6efff26aa94946, 0xb41858f73c389602, "How can you write a big system without C++? -Paul Glick"}, - {0xe7fcf1006b503b61, 0x27db187fc15bbc72, "This is a test of the emergency broadcast system."}, + {0x0, 0x0, "", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\x00\x00\x00\x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee\x00\x00\x00\x00\x00\x00\x00\x00"}, + {0x3420000000000000, 0x330284772e652b05, "a", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\x00\x00\x00\x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee\x00\x00\x00\x00\x00\x00\x00\x00"}, + {0x36c4200000000000, 0xbc6573200e84b046, "ab", "crc\x02s\xba\x84\x84\xbb\xcd]\xef4 \x00\x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee3\x02\x84w.e+\x05"}, + {0x3776c42000000000, 0x2cd8094a1a277627, "abc", "crc\x02s\xba\x84\x84\xbb\xcd]\xef4 \x00\x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee3\x02\x84w.e+\x05"}, + {0x336776c420000000, 0x3c9d28596e5960ba, "abcd", "crc\x02s\xba\x84\x84\xbb\xcd]\xef6\xc4 \x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee\xbces \x0e\x84\xb0F"}, + {0x32d36776c4200000, 0x40bdf58fb0895f2, "abcde", "crc\x02s\xba\x84\x84\xbb\xcd]\xef6\xc4 \x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee\xbces \x0e\x84\xb0F"}, + {0x3002d36776c42000, 0xd08e9f8545a700f4, "abcdef", "crc\x02s\xba\x84\x84\xbb\xcd]\xef7v\xc4 \x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee,\xd8\tJ\x1a'v'"}, + {0x31b002d36776c420, 0xec20a3a8cc710e66, "abcdefg", "crc\x02s\xba\x84\x84\xbb\xcd]\xef7v\xc4 \x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee,\xd8\tJ\x1a'v'"}, + {0xe21b002d36776c4, 0x67b4f30a647a0c59, "abcdefgh", "crc\x02s\xba\x84\x84\xbb\xcd]\xef3gv\xc4 \x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee<\x9d(YnY`\xba"}, + {0x8b6e21b002d36776, 0x9966f6c89d56ef8e, "abcdefghi", "crc\x02s\xba\x84\x84\xbb\xcd]\xef3gv\xc4 \x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee<\x9d(YnY`\xba"}, + {0x7f5b6e21b002d367, 0x32093a2ecd5773f4, "abcdefghij", "crc\x02s\xba\x84\x84\xbb\xcd]\xef2\xd3gv\xc4 \x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee\x04\v\xdfX\xfb\b\x95\xf2"}, + {0x8ec0e7c835bf9cdf, 0x8a0825223ea6d221, "Discard medicine more than two years old.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xc6\xc0\f\xac'\x11\x12\xd5", "crc\x02`&\x9aR\xe1\xb7\xfee\xfd%\xc0&\xa0R\xef\x95"}, + {0xc7db1759e2be5ab4, 0x8562c0ac2ab9a00d, "He who has a shady past knows that nice guys finish last.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\t\xcb\xd15X[r\t", "crc\x02`&\x9aR\xe1\xb7\xfee\a\x02\xe8|+\xc1\x06\xe3"}, + {0xfbf9d9603a6fa020, 0x3ee2a39c083f38b4, "I wouldn't marry him with a ten foot pole.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\x19\xc8d\xbe\x84\x14\x87_", "crc\x02`&\x9aR\xe1\xb7\xfee˷\xd3\xeeG\xdcE\x8c"}, + {0xeafc4211a6daa0ef, 0x1f603830353e518a, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xad\x1b*\xc0\xb1\xf3i(", "crc\x02`&\x9aR\xe1\xb7\xfee\xa7\x8a\xdb\xf6\xd2R\t\x96"}, + {0x3e05b21c7a4dc4da, 0x2fd681d7b2421fd, "The days of the digital watch are numbered. -Tom Stoppard", "crc\x02s\xba\x84\x84\xbb\xcd]\xefv78\x1ak\x02\x8f\xff", "crc\x02`&\x9aR\xe1\xb7\xfeeT\xcbl\x10\xfb\x87K*"}, + {0x5255866ad6ef28a6, 0x790ef2b16a745a41, "Nepal premier won't resign.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xcbf\x11R\xbfh\xde\xc9", "crc\x02`&\x9aR\xe1\xb7\xfee6\x13ُ\x06_\xbd\x9a"}, + {0x8a79895be1e9c361, 0x3ef8f06daccdcddf, "For every action there is an equal and opposite government program.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xf3pV\x01c_Wu", "crc\x02`&\x9aR\xe1\xb7\xfee\xe7\xc6\n\b\x12FL\xa0"}, + {0x8878963a649d4916, 0x49e41b2660b106d, "His money is twice tainted: 'taint yours and 'taint mine.", "crc\x02s\xba\x84\x84\xbb\xcd]\xefñ\xff\xf1\xe0/Δ", "crc\x02`&\x9aR\xe1\xb7\xfeeOL/\xb1\xec\xa2\x14\x87"}, + {0xa7b9d53ea87eb82f, 0x561cc0cfa235ac68, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "crc\x02s\xba\x84\x84\xbb\xcd]\xefݸa\xe1\xb5\xf8\xb9W", "crc\x02`&\x9aR\xe1\xb7\xfee\x87)GQ\x03\xf4K\t"}, + {0xdb6805c0966a2f9c, 0xd4fe9ef082e69f59, "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "crc\x02s\xba\x84\x84\xbb\xcd]\xefV\xba\x12\x91\x81\x1fNU", "crc\x02`&\x9aR\xe1\xb7\xfee\n\xb8\x81v?\xdeL\xcb"}, + {0xf3553c65dacdadd2, 0xe3b5e46cd8d63a4d, "size: a.out: bad magic", "crc\x02s\xba\x84\x84\xbb\xcd]\xefG\xad\xbc\xb2\xa8y\xc9\xdc", "crc\x02`&\x9aR\xe1\xb7\xfee\xcc\xce\xe5\xe6\x89p\x01\xb8"}, + {0x9d5e034087a676b9, 0x865aaf6b94f2a051, "The major problem is with sendmail. -Mark Horton", "crc\x02s\xba\x84\x84\xbb\xcd]\uf8acn\x8aT;&\xd5", "crc\x02`&\x9aR\xe1\xb7\xfeeFf\x9c\x1f\xc9x\xbfa"}, + {0xa6db2d7f8da96417, 0x7eca10d2f8136eb4, "Give me a rock, paper and scissors and I will move the world. CCFestoon", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xeb\x18\xbf\xf9}\x91\xe5|", "crc\x02`&\x9aR\xe1\xb7\xfeea\x9e\x05:\xce[\xe7\x19"}, + {0x325e00cd2fe819f9, 0xd7dd118c98e98727, "If the enemy is within range, then so are you.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef^5k\xd0Aj_{", "crc\x02`&\x9aR\xe1\xb7\xfee\v#\x99\xa8r\x83YR"}, + {0x88c6600ce58ae4c6, 0x70fb33c119c29318, "It's well we cannot hear the screams/That we create in others' dreams.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef|\xb5\x02\xdcw\x18/\x86", "crc\x02`&\x9aR\xe1\xb7\xfee]\x9d-\xed\x8c\xf9r9"}, + {0x28c4a3f3b769e078, 0x57c891e39a97d9b7, "You remind me of a TV show, but that's all right: I watch it anyway.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\x03\x8bd\x1c\xb0_\x16\x98", "crc\x02`&\x9aR\xe1\xb7\xfee\xafW\x98\xaa\"\xe7\xd7|"}, + {0xa698a34c9d9f1dca, 0xa1f46ba20ad06eb7, "C is as portable as Stonehedge!!", "crc\x02s\xba\x84\x84\xbb\xcd]\xef.P\xe1I\xc6pi\xdc", "crc\x02`&\x9aR\xe1\xb7\xfee֚\x06\x01(\xc0\x1e\x8b"}, + {0xf6c1e2a8c26c5cfc, 0x7ad25fafa1710407, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xf7\xa04\x8a\xf2o\xe0;", "crc\x02`&\x9aR\xe1\xb7\xfee<[\xd2%\x9em\x94\x04"}, + {0xd402559dfe9b70c, 0x73cef1666185c13f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\u007f\xae\xb9\xbaX=\x19v", "crc\x02`&\x9aR\xe1\xb7\xfee\xb2˦Y\xc5\xd0G\x03"}, + {0xdb6efff26aa94946, 0xb41858f73c389602, "How can you write a big system without C++? -Paul Glick", "crc\x02s\xba\x84\x84\xbb\xcd]\xefa\xed$js\xb9\xa5A", "crc\x02`&\x9aR\xe1\xb7\xfeeZm\x96\x8a\xe2\xaf\x13p"}, + {0xe7fcf1006b503b61, 0x27db187fc15bbc72, "This is a test of the emergency broadcast system.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef}\xee[q\x16\xcb\xe4\x8d", "crc\x02`&\x9aR\xe1\xb7\xfee\xb1\x93] \xeb\xa9am"}, } func TestGolden(t *testing.T) { @@ -72,6 +75,87 @@ func TestGolden(t *testing.T) { } } +func TestGoldenMarshal(t *testing.T) { + t.Run("ISO", func(t *testing.T) { + table := MakeTable(ISO) + for _, g := range golden { + h := New(table) + h2 := New(table) + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfStateISO { + t.Errorf("ISO crc64(%q) state = %q, want %q", g.in, state, g.halfStateISO) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if h.Sum64() != h2.Sum64() { + t.Errorf("ISO crc64(%s) = 0x%x != marshaled (0x%x)", g.in, h.Sum64(), h2.Sum64()) + } + } + }) + t.Run("ECMA", func(t *testing.T) { + table := MakeTable(ECMA) + for _, g := range golden { + h := New(table) + h2 := New(table) + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfStateECMA { + t.Errorf("ECMA crc64(%q) state = %q, want %q", g.in, state, g.halfStateECMA) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if h.Sum64() != h2.Sum64() { + t.Errorf("ECMA crc64(%s) = 0x%x != marshaled (0x%x)", g.in, h.Sum64(), h2.Sum64()) + } + } + }) +} + +func TestMarshalTableMismatch(t *testing.T) { + h1 := New(MakeTable(ISO)) + h2 := New(MakeTable(ECMA)) + + state1, err := h1.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state1); err == nil { + t.Errorf("no error when one was expected") + } +} + func bench(b *testing.B, poly uint64, size int64) { b.SetBytes(size) data := make([]byte, size) diff --git a/libgo/go/hash/example_test.go b/libgo/go/hash/example_test.go new file mode 100644 index 0000000..49dc8fc --- /dev/null +++ b/libgo/go/hash/example_test.go @@ -0,0 +1,53 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package hash_test + +import ( + "bytes" + "crypto/sha256" + "encoding" + "fmt" + "log" +) + +func Example_binaryMarshaler() { + const ( + input1 = "The tunneling gopher digs downwards, " + input2 = "unaware of what he will find." + ) + + first := sha256.New() + first.Write([]byte(input1)) + + marshaler, ok := first.(encoding.BinaryMarshaler) + if !ok { + log.Fatal("first does not implement encoding.BinaryMarshaler") + } + state, err := marshaler.MarshalBinary() + if err != nil { + log.Fatal("unable to marshal hash:", err) + } + + second := sha256.New() + + unmarshaler, ok := second.(encoding.BinaryUnmarshaler) + if !ok { + log.Fatal("second does not implement encoding.BinaryUnmarshaler") + } + if err := unmarshaler.UnmarshalBinary(state); err != nil { + log.Fatal("unable to unmarshal hash:", err) + } + + first.Write([]byte(input2)) + second.Write([]byte(input2)) + + fmt.Printf("%x\n", first.Sum(nil)) + fmt.Println(bytes.Equal(first.Sum(nil), second.Sum(nil))) + // Output: + // 57d51a066f3a39942649cd9a76c77e97ceab246756ff3888659e6aa5a07f4a52 + // true +} diff --git a/libgo/go/hash/fnv/fnv.go b/libgo/go/hash/fnv/fnv.go index 3d2df73..7662315d 100644 --- a/libgo/go/hash/fnv/fnv.go +++ b/libgo/go/hash/fnv/fnv.go @@ -6,9 +6,14 @@ // created by Glenn Fowler, Landon Curt Noll, and Phong Vo. // See // https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function. +// +// All the hash.Hash implementations returned by this package also +// implement encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to +// marshal and unmarshal the internal state of the hash. package fnv import ( + "errors" "hash" ) @@ -215,3 +220,163 @@ func (s *sum128a) Sum(in []byte) []byte { byte(s[1]>>56), byte(s[1]>>48), byte(s[1]>>40), byte(s[1]>>32), byte(s[1]>>24), byte(s[1]>>16), byte(s[1]>>8), byte(s[1]), ) } + +const ( + magic32 = "fnv\x01" + magic32a = "fnv\x02" + magic64 = "fnv\x03" + magic64a = "fnv\x04" + magic128 = "fnv\x05" + magic128a = "fnv\x06" + marshaledSize32 = len(magic32) + 4 + marshaledSize64 = len(magic64) + 8 + marshaledSize128 = len(magic128) + 8*2 +) + +func (s *sum32) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize32) + b = append(b, magic32...) + b = appendUint32(b, uint32(*s)) + return b, nil +} + +func (s *sum32a) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize32) + b = append(b, magic32a...) + b = appendUint32(b, uint32(*s)) + return b, nil +} + +func (s *sum64) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize64) + b = append(b, magic64...) + b = appendUint64(b, uint64(*s)) + return b, nil + +} + +func (s *sum64a) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize64) + b = append(b, magic64a...) + b = appendUint64(b, uint64(*s)) + return b, nil +} + +func (s *sum128) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize128) + b = append(b, magic128...) + b = appendUint64(b, s[0]) + b = appendUint64(b, s[1]) + return b, nil +} + +func (s *sum128a) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize128) + b = append(b, magic128a...) + b = appendUint64(b, s[0]) + b = appendUint64(b, s[1]) + return b, nil +} + +func (s *sum32) UnmarshalBinary(b []byte) error { + if len(b) < len(magic32) || string(b[:len(magic32)]) != magic32 { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize32 { + return errors.New("hash/fnv: invalid hash state size") + } + *s = sum32(readUint32(b[4:])) + return nil +} + +func (s *sum32a) UnmarshalBinary(b []byte) error { + if len(b) < len(magic32a) || string(b[:len(magic32a)]) != magic32a { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize32 { + return errors.New("hash/fnv: invalid hash state size") + } + *s = sum32a(readUint32(b[4:])) + return nil +} + +func (s *sum64) UnmarshalBinary(b []byte) error { + if len(b) < len(magic64) || string(b[:len(magic64)]) != magic64 { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize64 { + return errors.New("hash/fnv: invalid hash state size") + } + *s = sum64(readUint64(b[4:])) + return nil +} + +func (s *sum64a) UnmarshalBinary(b []byte) error { + if len(b) < len(magic64a) || string(b[:len(magic64a)]) != magic64a { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize64 { + return errors.New("hash/fnv: invalid hash state size") + } + *s = sum64a(readUint64(b[4:])) + return nil +} + +func (s *sum128) UnmarshalBinary(b []byte) error { + if len(b) < len(magic128) || string(b[:len(magic128)]) != magic128 { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize128 { + return errors.New("hash/fnv: invalid hash state size") + } + s[0] = readUint64(b[4:]) + s[1] = readUint64(b[12:]) + return nil +} + +func (s *sum128a) UnmarshalBinary(b []byte) error { + if len(b) < len(magic128a) || string(b[:len(magic128a)]) != magic128a { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize128 { + return errors.New("hash/fnv: invalid hash state size") + } + s[0] = readUint64(b[4:]) + s[1] = readUint64(b[12:]) + return nil +} + +func readUint32(b []byte) uint32 { + _ = b[3] + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + +func appendUint32(b []byte, x uint32) []byte { + a := [4]byte{ + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func appendUint64(b []byte, x uint64) []byte { + a := [8]byte{ + byte(x >> 56), + byte(x >> 48), + byte(x >> 40), + byte(x >> 32), + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func readUint64(b []byte) uint64 { + _ = b[7] + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} diff --git a/libgo/go/hash/fnv/fnv_test.go b/libgo/go/hash/fnv/fnv_test.go index 7da15ba..7b1f7a3 100644 --- a/libgo/go/hash/fnv/fnv_test.go +++ b/libgo/go/hash/fnv/fnv_test.go @@ -6,56 +6,59 @@ package fnv import ( "bytes" + "encoding" "encoding/binary" "hash" + "io" "testing" ) type golden struct { - sum []byte - text string + out []byte + in string + halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal } var golden32 = []golden{ - {[]byte{0x81, 0x1c, 0x9d, 0xc5}, ""}, - {[]byte{0x05, 0x0c, 0x5d, 0x7e}, "a"}, - {[]byte{0x70, 0x77, 0x2d, 0x38}, "ab"}, - {[]byte{0x43, 0x9c, 0x2f, 0x4b}, "abc"}, + {[]byte{0x81, 0x1c, 0x9d, 0xc5}, "", "fnv\x01\x81\x1c\x9d\xc5"}, + {[]byte{0x05, 0x0c, 0x5d, 0x7e}, "a", "fnv\x01\x81\x1c\x9d\xc5"}, + {[]byte{0x70, 0x77, 0x2d, 0x38}, "ab", "fnv\x01\x05\f]~"}, + {[]byte{0x43, 0x9c, 0x2f, 0x4b}, "abc", "fnv\x01\x05\f]~"}, } var golden32a = []golden{ - {[]byte{0x81, 0x1c, 0x9d, 0xc5}, ""}, - {[]byte{0xe4, 0x0c, 0x29, 0x2c}, "a"}, - {[]byte{0x4d, 0x25, 0x05, 0xca}, "ab"}, - {[]byte{0x1a, 0x47, 0xe9, 0x0b}, "abc"}, + {[]byte{0x81, 0x1c, 0x9d, 0xc5}, "", "fnv\x02\x81\x1c\x9d\xc5"}, + {[]byte{0xe4, 0x0c, 0x29, 0x2c}, "a", "fnv\x02\x81\x1c\x9d\xc5"}, + {[]byte{0x4d, 0x25, 0x05, 0xca}, "ab", "fnv\x02\xe4\f),"}, + {[]byte{0x1a, 0x47, 0xe9, 0x0b}, "abc", "fnv\x02\xe4\f),"}, } var golden64 = []golden{ - {[]byte{0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25}, ""}, - {[]byte{0xaf, 0x63, 0xbd, 0x4c, 0x86, 0x01, 0xb7, 0xbe}, "a"}, - {[]byte{0x08, 0x32, 0x67, 0x07, 0xb4, 0xeb, 0x37, 0xb8}, "ab"}, - {[]byte{0xd8, 0xdc, 0xca, 0x18, 0x6b, 0xaf, 0xad, 0xcb}, "abc"}, + {[]byte{0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25}, "", "fnv\x03\xcb\xf2\x9c\xe4\x84\"#%"}, + {[]byte{0xaf, 0x63, 0xbd, 0x4c, 0x86, 0x01, 0xb7, 0xbe}, "a", "fnv\x03\xcb\xf2\x9c\xe4\x84\"#%"}, + {[]byte{0x08, 0x32, 0x67, 0x07, 0xb4, 0xeb, 0x37, 0xb8}, "ab", "fnv\x03\xafc\xbdL\x86\x01\xb7\xbe"}, + {[]byte{0xd8, 0xdc, 0xca, 0x18, 0x6b, 0xaf, 0xad, 0xcb}, "abc", "fnv\x03\xafc\xbdL\x86\x01\xb7\xbe"}, } var golden64a = []golden{ - {[]byte{0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25}, ""}, - {[]byte{0xaf, 0x63, 0xdc, 0x4c, 0x86, 0x01, 0xec, 0x8c}, "a"}, - {[]byte{0x08, 0x9c, 0x44, 0x07, 0xb5, 0x45, 0x98, 0x6a}, "ab"}, - {[]byte{0xe7, 0x1f, 0xa2, 0x19, 0x05, 0x41, 0x57, 0x4b}, "abc"}, + {[]byte{0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25}, "", "fnv\x04\xcb\xf2\x9c\xe4\x84\"#%"}, + {[]byte{0xaf, 0x63, 0xdc, 0x4c, 0x86, 0x01, 0xec, 0x8c}, "a", "fnv\x04\xcb\xf2\x9c\xe4\x84\"#%"}, + {[]byte{0x08, 0x9c, 0x44, 0x07, 0xb5, 0x45, 0x98, 0x6a}, "ab", "fnv\x04\xafc\xdcL\x86\x01\xec\x8c"}, + {[]byte{0xe7, 0x1f, 0xa2, 0x19, 0x05, 0x41, 0x57, 0x4b}, "abc", "fnv\x04\xafc\xdcL\x86\x01\xec\x8c"}, } var golden128 = []golden{ - {[]byte{0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d}, ""}, - {[]byte{0xd2, 0x28, 0xcb, 0x69, 0x10, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x14, 0x1e}, "a"}, - {[]byte{0x8, 0x80, 0x94, 0x5a, 0xee, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0x26, 0xc0, 0x88}, "ab"}, - {[]byte{0xa6, 0x8b, 0xb2, 0xa4, 0x34, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x78, 0xc6, 0xae, 0xe7, 0x3b}, "abc"}, + {[]byte{0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d}, "", "fnv\x05lb'.\a\xbb\x01Bb\xb8!ub\x95ō"}, + {[]byte{0xd2, 0x28, 0xcb, 0x69, 0x10, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x14, 0x1e}, "a", "fnv\x05lb'.\a\xbb\x01Bb\xb8!ub\x95ō"}, + {[]byte{0x8, 0x80, 0x94, 0x5a, 0xee, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0x26, 0xc0, 0x88}, "ab", "fnv\x05\xd2(\xcbi\x10\x1a\x8c\xafx\x91+pNJ\x14\x1e"}, + {[]byte{0xa6, 0x8b, 0xb2, 0xa4, 0x34, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x78, 0xc6, 0xae, 0xe7, 0x3b}, "abc", "fnv\x05\xd2(\xcbi\x10\x1a\x8c\xafx\x91+pNJ\x14\x1e"}, } var golden128a = []golden{ - {[]byte{0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d}, ""}, - {[]byte{0xd2, 0x28, 0xcb, 0x69, 0x6f, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x89, 0x64}, "a"}, - {[]byte{0x08, 0x80, 0x95, 0x44, 0xbb, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0xb6, 0x9a, 0x62}, "ab"}, - {[]byte{0xa6, 0x8d, 0x62, 0x2c, 0xec, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x79, 0x77, 0xaf, 0x7f, 0x3b}, "abc"}, + {[]byte{0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d}, "", "fnv\x06lb'.\a\xbb\x01Bb\xb8!ub\x95ō"}, + {[]byte{0xd2, 0x28, 0xcb, 0x69, 0x6f, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x89, 0x64}, "a", "fnv\x06lb'.\a\xbb\x01Bb\xb8!ub\x95ō"}, + {[]byte{0x08, 0x80, 0x95, 0x44, 0xbb, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0xb6, 0x9a, 0x62}, "ab", "fnv\x06\xd2(\xcbio\x1a\x8c\xafx\x91+pNJ\x89d"}, + {[]byte{0xa6, 0x8d, 0x62, 0x2c, 0xec, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x79, 0x77, 0xaf, 0x7f, 0x3b}, "abc", "fnv\x06\xd2(\xcbio\x1a\x8c\xafx\x91+pNJ\x89d"}, } func TestGolden32(t *testing.T) { @@ -85,19 +88,67 @@ func TestGolden128a(t *testing.T) { func testGolden(t *testing.T, hash hash.Hash, gold []golden) { for _, g := range gold { hash.Reset() - done, error := hash.Write([]byte(g.text)) + done, error := hash.Write([]byte(g.in)) if error != nil { t.Fatalf("write error: %s", error) } - if done != len(g.text) { - t.Fatalf("wrote only %d out of %d bytes", done, len(g.text)) + if done != len(g.in) { + t.Fatalf("wrote only %d out of %d bytes", done, len(g.in)) } - if actual := hash.Sum(nil); !bytes.Equal(g.sum, actual) { - t.Errorf("hash(%q) = 0x%x want 0x%x", g.text, actual, g.sum) + if actual := hash.Sum(nil); !bytes.Equal(g.out, actual) { + t.Errorf("hash(%q) = 0x%x want 0x%x", g.in, actual, g.out) } } } +func TestGoldenMarshal(t *testing.T) { + tests := []struct { + name string + newHash func() hash.Hash + gold []golden + }{ + {"32", func() hash.Hash { return New32() }, golden32}, + {"32a", func() hash.Hash { return New32a() }, golden32a}, + {"64", func() hash.Hash { return New64() }, golden64}, + {"64a", func() hash.Hash { return New64a() }, golden64a}, + {"128", func() hash.Hash { return New128() }, golden128}, + {"128a", func() hash.Hash { return New128a() }, golden128a}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for _, g := range tt.gold { + h := tt.newHash() + h2 := tt.newHash() + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfState { + t.Errorf("checksum(%q) state = %q, want %q", g.in, state, g.halfState) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if actual, actual2 := h.Sum(nil), h2.Sum(nil); !bytes.Equal(actual, actual2) { + t.Errorf("hash(%q) = 0x%x != marshaled 0x%x", g.in, actual, actual2) + } + } + }) + } +} + func TestIntegrity32(t *testing.T) { testIntegrity(t, New32()) } diff --git a/libgo/go/hash/hash.go b/libgo/go/hash/hash.go index 8d138d0..62cf6a4 100644 --- a/libgo/go/hash/hash.go +++ b/libgo/go/hash/hash.go @@ -8,6 +8,21 @@ package hash import "io" // Hash is the common interface implemented by all hash functions. +// +// Hash implementations in the standard library (e.g. hash/crc32 and +// crypto/sha256) implement the encoding.BinaryMarshaler and +// encoding.BinaryUnmarshaler interfaces. Marshaling a hash implementation +// allows its internal state to be saved and used for additional processing +// later, without having to re-write the data previously written to the hash. +// The hash state may contain portions of the input in its original form, +// which users are expected to handle for any possible security implications. +// +// Compatibility: Any future changes to hash or crypto packages will endeavor +// to maintain compatibility with state encoded using previous versions. +// That is, any released versions of the packages should be able to +// decode data written with any previously released version, +// subject to issues such as security fixes. +// See the Go compatibility document for background: https://golang.org/doc/go1compat type Hash interface { // Write (via the embedded io.Writer interface) adds more data to the running hash. // It never returns an error. diff --git a/libgo/go/hash/marshal_test.go b/libgo/go/hash/marshal_test.go new file mode 100644 index 0000000..3091f7a --- /dev/null +++ b/libgo/go/hash/marshal_test.go @@ -0,0 +1,107 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that the hashes in the standard library implement +// BinaryMarshaler, BinaryUnmarshaler, +// and lock in the current representations. + +package hash_test + +import ( + "bytes" + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "encoding" + "encoding/hex" + "hash" + "hash/adler32" + "hash/crc32" + "hash/crc64" + "hash/fnv" + "testing" +) + +func fromHex(s string) []byte { + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +var marshalTests = []struct { + name string + new func() hash.Hash + golden []byte +}{ + {"adler32", func() hash.Hash { return adler32.New() }, fromHex("61646c01460a789d")}, + {"crc32", func() hash.Hash { return crc32.NewIEEE() }, fromHex("63726301ca87914dc956d3e8")}, + {"crc64", func() hash.Hash { return crc64.New(crc64.MakeTable(crc64.ISO)) }, fromHex("6372630273ba8484bbcd5def5d51c83c581695be")}, + {"fnv32", func() hash.Hash { return fnv.New32() }, fromHex("666e760171ba3d77")}, + {"fnv32a", func() hash.Hash { return fnv.New32a() }, fromHex("666e76027439f86f")}, + {"fnv64", func() hash.Hash { return fnv.New64() }, fromHex("666e7603cc64e0e97692c637")}, + {"fnv64a", func() hash.Hash { return fnv.New64a() }, fromHex("666e7604c522af9b0dede66f")}, + {"fnv128", func() hash.Hash { return fnv.New128() }, fromHex("666e760561587a70a0f66d7981dc980e2cabbaf7")}, + {"fnv128a", func() hash.Hash { return fnv.New128a() }, fromHex("666e7606a955802b0136cb67622b461d9f91e6ff")}, + {"md5", md5.New, fromHex("6d643501a91b0023007aa14740a3979210b5f024c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha1", sha1.New, fromHex("736861016dad5acb4dc003952f7a0b352ee5537ec381a228c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha224", sha256.New224, fromHex("73686102f8b92fc047c9b4d82f01a6370841277b7a0d92108440178c83db855a8e66c2d9c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha256", sha256.New, fromHex("736861032bed68b99987cae48183b2b049d393d0050868e4e8ba3730e9112b08765929b7c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha384", sha512.New384, fromHex("736861046f1664d213dd802f7c47bc50637cf93592570a2b8695839148bf38341c6eacd05326452ef1cbe64d90f1ef73bb5ac7d2803565467d0ddb10c5ee3fc050f9f0c1808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha512_224", sha512.New512_224, fromHex("736861056f1a450ec15af20572d0d1ee6518104d7cbbbe79a038557af5450ed7dbd420b53b7335209e951b4d9aff401f90549b9604fa3d823fbb8581c73582a88aa84022808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha512_256", sha512.New512_256, fromHex("736861067c541f1d1a72536b1f5dad64026bcc7c508f8a2126b51f46f8b9bff63a26fee70980718031e96832e95547f4fe76160ff84076db53b4549b86354af8e17b5116808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha512", sha512.New, fromHex("736861078e03953cd57cd6879321270afa70c5827bb5b69be59a8f0130147e94f2aedf7bdc01c56c92343ca8bd837bb7f0208f5a23e155694516b6f147099d491a30b151808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, +} + +func TestMarshalHash(t *testing.T) { + for _, tt := range marshalTests { + t.Run(tt.name, func(t *testing.T) { + buf := make([]byte, 256) + for i := range buf { + buf[i] = byte(i) + } + + h := tt.new() + h.Write(buf[:256]) + sum := h.Sum(nil) + + h2 := tt.new() + h3 := tt.new() + const split = 249 + for i := 0; i < split; i++ { + h2.Write(buf[i : i+1]) + } + h2m, ok := h2.(encoding.BinaryMarshaler) + if !ok { + t.Fatalf("Hash does not implement MarshalBinary") + } + enc, err := h2m.MarshalBinary() + if err != nil { + t.Fatalf("MarshalBinary: %v", err) + } + if !bytes.Equal(enc, tt.golden) { + t.Errorf("MarshalBinary = %x, want %x", enc, tt.golden) + } + h3u, ok := h3.(encoding.BinaryUnmarshaler) + if !ok { + t.Fatalf("Hash does not implement UnmarshalBinary") + } + if err := h3u.UnmarshalBinary(enc); err != nil { + t.Fatalf("UnmarshalBinary: %v", err) + } + h2.Write(buf[split:]) + h3.Write(buf[split:]) + sum2 := h2.Sum(nil) + sum3 := h3.Sum(nil) + if !bytes.Equal(sum2, sum) { + t.Fatalf("Sum after MarshalBinary = %x, want %x", sum2, sum) + } + if !bytes.Equal(sum3, sum) { + t.Fatalf("Sum after UnmarshalBinary = %x, want %x", sum3, sum) + } + }) + } +} |