forked from gnolang/gno
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
<!-- please provide a detailed description of the changes made in this pull request. --> Add hash stdlib (especially adler32) and add encoding for dependency ## relate issue gnolang#1267
- Loading branch information
Showing
5 changed files
with
336 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright 2013 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. | ||
|
||
// Package encoding defines interfaces shared by other packages that | ||
// convert data to and from byte-level and textual representations. | ||
// Packages that check for these interfaces include encoding/gob, | ||
// encoding/json, and encoding/xml. As a result, implementing an | ||
// interface once can make a type useful in multiple encodings. | ||
// Standard types that implement these interfaces include time.Time and net.IP. | ||
// The interfaces come in pairs that produce and consume encoded data. | ||
// | ||
// Adding encoding/decoding methods to existing types may constitute a breaking change, | ||
// as they can be used for serialization in communicating with programs | ||
// written with different library versions. | ||
// The policy for packages maintained by the Go project is to only allow | ||
// the addition of marshaling functions if no existing, reasonable marshaling exists. | ||
package encoding | ||
|
||
// BinaryMarshaler is the interface implemented by an object that can | ||
// marshal itself into a binary form. | ||
// | ||
// MarshalBinary encodes the receiver into a binary form and returns the result. | ||
type BinaryMarshaler interface { | ||
MarshalBinary() (data []byte, err error) | ||
} | ||
|
||
// BinaryUnmarshaler is the interface implemented by an object that can | ||
// unmarshal a binary representation of itself. | ||
// | ||
// UnmarshalBinary must be able to decode the form generated by MarshalBinary. | ||
// UnmarshalBinary must copy the data if it wishes to retain the data | ||
// after returning. | ||
type BinaryUnmarshaler interface { | ||
UnmarshalBinary(data []byte) error | ||
} | ||
|
||
// TextMarshaler is the interface implemented by an object that can | ||
// marshal itself into a textual form. | ||
// | ||
// MarshalText encodes the receiver into UTF-8-encoded text and returns the result. | ||
type TextMarshaler interface { | ||
MarshalText() (text []byte, err error) | ||
} | ||
|
||
// TextUnmarshaler is the interface implemented by an object that can | ||
// unmarshal a textual representation of itself. | ||
// | ||
// UnmarshalText must be able to decode the form generated by MarshalText. | ||
// UnmarshalText must copy the text if it wishes to retain the text | ||
// after returning. | ||
type TextUnmarshaler interface { | ||
UnmarshalText(text []byte) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
// Copyright 2009 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. | ||
|
||
// Package adler32 implements the Adler-32 checksum. | ||
// | ||
// It is defined in RFC 1950: | ||
// | ||
// Adler-32 is composed of two sums accumulated per byte: s1 is | ||
// the sum of all bytes, s2 is the sum of all s1 values. Both sums | ||
// are done modulo 65521. s1 is initialized to 1, s2 to zero. The | ||
// Adler-32 checksum is stored as s2*65536 + s1 in most- | ||
// significant-byte first (network) order. | ||
package adler32 | ||
|
||
import ( | ||
"errors" | ||
"hash" | ||
) | ||
|
||
const ( | ||
// mod is the largest prime that is less than 65536. | ||
mod = 65521 | ||
// nmax is the largest n such that | ||
// 255 * n * (n+1) / 2 + (n+1) * (mod-1) <= 2^32-1. | ||
// It is mentioned in RFC 1950 (search for "5552"). | ||
nmax = 5552 | ||
) | ||
|
||
// The size of an Adler-32 checksum in bytes. | ||
const Size = 4 | ||
|
||
// digest represents the partial evaluation of a checksum. | ||
// The low 16 bits are s1, the high 16 bits are s2. | ||
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. 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() | ||
return d | ||
} | ||
|
||
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) | ||
for len(p) > 0 { | ||
var q []byte | ||
if len(p) > nmax { | ||
p, q = p[:nmax], p[nmax:] | ||
} | ||
for len(p) >= 4 { | ||
s1 += uint32(p[0]) | ||
s2 += s1 | ||
s1 += uint32(p[1]) | ||
s2 += s1 | ||
s1 += uint32(p[2]) | ||
s2 += s1 | ||
s1 += uint32(p[3]) | ||
s2 += s1 | ||
p = p[4:] | ||
} | ||
for _, x := range p { | ||
s1 += uint32(x) | ||
s2 += s1 | ||
} | ||
s1 %= mod | ||
s2 %= mod | ||
p = q | ||
} | ||
return digest(s2<<16 | s1) | ||
} | ||
|
||
func (d *digest) Write(p []byte) (nn int, err error) { | ||
*d = update(*d, p) | ||
return len(p), nil | ||
} | ||
|
||
func (d *digest) Sum32() uint32 { return uint32(*d) } | ||
|
||
func (d *digest) Sum(in []byte) []byte { | ||
s := uint32(*d) | ||
return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s)) | ||
} | ||
|
||
// Checksum returns the Adler-32 checksum of data. | ||
func Checksum(data []byte) uint32 { return uint32(update(1, data)) } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// Copyright 2009 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. | ||
|
||
// Package hash provides interfaces for hash functions. | ||
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. | ||
io.Writer | ||
|
||
// Sum appends the current hash to b and returns the resulting slice. | ||
// It does not change the underlying hash state. | ||
Sum(b []byte) []byte | ||
|
||
// Reset resets the Hash to its initial state. | ||
Reset() | ||
|
||
// Size returns the number of bytes Sum will return. | ||
Size() int | ||
|
||
// BlockSize returns the hash's underlying block size. | ||
// The Write method must be able to accept any amount | ||
// of data, but it may operate more efficiently if all writes | ||
// are a multiple of the block size. | ||
BlockSize() int | ||
} | ||
|
||
// Hash32 is the common interface implemented by all 32-bit hash functions. | ||
type Hash32 interface { | ||
Hash | ||
Sum32() uint32 | ||
} | ||
|
||
// Hash64 is the common interface implemented by all 64-bit hash functions. | ||
type Hash64 interface { | ||
Hash | ||
Sum64() uint64 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// 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 | ||
|
||
import ( | ||
"bytes" | ||
"crypto/md5" | ||
"crypto/sha1" | ||
"crypto/sha256" | ||
"encoding" | ||
"encoding/hex" | ||
"hash" | ||
"hash/adler32" | ||
"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")}, | ||
} | ||
|
||
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) | ||
} | ||
}) | ||
} | ||
} |