|
|
@@ -92,6 +92,8 @@ func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) }
|
|
|
// values equal or greater than:
|
|
|
// - 32 if BLAKE2b is used as a hash function (The key is zero bytes long).
|
|
|
// - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long).
|
|
|
+// When the key is nil, the returned hash.Hash implements BinaryMarshaler
|
|
|
+// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
|
|
|
func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) }
|
|
|
|
|
|
func newDigest(hashSize int, key []byte) (*digest, error) {
|
|
|
@@ -150,6 +152,50 @@ type digest struct {
|
|
|
keyLen int
|
|
|
}
|
|
|
|
|
|
+const (
|
|
|
+ magic = "b2b"
|
|
|
+ marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1
|
|
|
+)
|
|
|
+
|
|
|
+func (d *digest) MarshalBinary() ([]byte, error) {
|
|
|
+ if d.keyLen != 0 {
|
|
|
+ return nil, errors.New("crypto/blake2b: cannot marshal MACs")
|
|
|
+ }
|
|
|
+ b := make([]byte, 0, marshaledSize)
|
|
|
+ b = append(b, magic...)
|
|
|
+ for i := 0; i < 8; i++ {
|
|
|
+ b = appendUint64(b, d.h[i])
|
|
|
+ }
|
|
|
+ b = appendUint64(b, d.c[0])
|
|
|
+ b = appendUint64(b, d.c[1])
|
|
|
+ // Maximum value for size is 64
|
|
|
+ b = append(b, byte(d.size))
|
|
|
+ b = append(b, d.block[:]...)
|
|
|
+ b = append(b, byte(d.offset))
|
|
|
+ return b, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (d *digest) UnmarshalBinary(b []byte) error {
|
|
|
+ if len(b) < len(magic) || string(b[:len(magic)]) != magic {
|
|
|
+ return errors.New("crypto/blake2b: invalid hash state identifier")
|
|
|
+ }
|
|
|
+ if len(b) != marshaledSize {
|
|
|
+ return errors.New("crypto/blake2b: invalid hash state size")
|
|
|
+ }
|
|
|
+ b = b[len(magic):]
|
|
|
+ for i := 0; i < 8; i++ {
|
|
|
+ b, d.h[i] = consumeUint64(b)
|
|
|
+ }
|
|
|
+ b, d.c[0] = consumeUint64(b)
|
|
|
+ b, d.c[1] = consumeUint64(b)
|
|
|
+ d.size = int(b[0])
|
|
|
+ b = b[1:]
|
|
|
+ copy(d.block[:], b[:BlockSize])
|
|
|
+ b = b[BlockSize:]
|
|
|
+ d.offset = int(b[0])
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
func (d *digest) BlockSize() int { return BlockSize }
|
|
|
|
|
|
func (d *digest) Size() int { return d.size }
|
|
|
@@ -219,3 +265,25 @@ func (d *digest) finalize(hash *[Size]byte) {
|
|
|
binary.LittleEndian.PutUint64(hash[8*i:], v)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func appendUint64(b []byte, x uint64) []byte {
|
|
|
+ var a [8]byte
|
|
|
+ binary.BigEndian.PutUint64(a[:], x)
|
|
|
+ return append(b, a[:]...)
|
|
|
+}
|
|
|
+
|
|
|
+func appendUint32(b []byte, x uint32) []byte {
|
|
|
+ var a [4]byte
|
|
|
+ binary.BigEndian.PutUint32(a[:], x)
|
|
|
+ return append(b, a[:]...)
|
|
|
+}
|
|
|
+
|
|
|
+func consumeUint64(b []byte) ([]byte, uint64) {
|
|
|
+ x := binary.BigEndian.Uint64(b)
|
|
|
+ return b[8:], x
|
|
|
+}
|
|
|
+
|
|
|
+func consumeUint32(b []byte) ([]byte, uint32) {
|
|
|
+ x := binary.BigEndian.Uint32(b)
|
|
|
+ return b[4:], x
|
|
|
+}
|