about summary refs log tree commit diff
path: root/vendor/golang.org/x/crypto/blake2b/blake2x.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/blake2b/blake2x.go')
-rw-r--r--vendor/golang.org/x/crypto/blake2b/blake2x.go177
1 files changed, 177 insertions, 0 deletions
diff --git a/vendor/golang.org/x/crypto/blake2b/blake2x.go b/vendor/golang.org/x/crypto/blake2b/blake2x.go
new file mode 100644
index 0000000..52c414d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/blake2b/blake2x.go
@@ -0,0 +1,177 @@
+// 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.
+
+package blake2b
+
+import (
+	"encoding/binary"
+	"errors"
+	"io"
+)
+
+// XOF defines the interface to hash functions that
+// support arbitrary-length output.
+type XOF interface {
+	// Write absorbs more data into the hash's state. It panics if called
+	// after Read.
+	io.Writer
+
+	// Read reads more output from the hash. It returns io.EOF if the limit
+	// has been reached.
+	io.Reader
+
+	// Clone returns a copy of the XOF in its current state.
+	Clone() XOF
+
+	// Reset resets the XOF to its initial state.
+	Reset()
+}
+
+// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
+// the length of the output is not known in advance.
+const OutputLengthUnknown = 0
+
+// magicUnknownOutputLength is a magic value for the output size that indicates
+// an unknown number of output bytes.
+const magicUnknownOutputLength = (1 << 32) - 1
+
+// maxOutputLength is the absolute maximum number of bytes to produce when the
+// number of output bytes is unknown.
+const maxOutputLength = (1 << 32) * 64
+
+// NewXOF creates a new variable-output-length hash. The hash either produce a
+// known number of bytes (1 <= size < 2**32-1), or an unknown number of bytes
+// (size == OutputLengthUnknown). In the latter case, an absolute limit of
+// 256GiB applies.
+//
+// A non-nil key turns the hash into a MAC. The key must between
+// zero and 32 bytes long.
+func NewXOF(size uint32, key []byte) (XOF, error) {
+	if len(key) > Size {
+		return nil, errKeySize
+	}
+	if size == magicUnknownOutputLength {
+		// 2^32-1 indicates an unknown number of bytes and thus isn't a
+		// valid length.
+		return nil, errors.New("blake2b: XOF length too large")
+	}
+	if size == OutputLengthUnknown {
+		size = magicUnknownOutputLength
+	}
+	x := &xof{
+		d: digest{
+			size:   Size,
+			keyLen: len(key),
+		},
+		length: size,
+	}
+	copy(x.d.key[:], key)
+	x.Reset()
+	return x, nil
+}
+
+type xof struct {
+	d                digest
+	length           uint32
+	remaining        uint64
+	cfg, root, block [Size]byte
+	offset           int
+	nodeOffset       uint32
+	readMode         bool
+}
+
+func (x *xof) Write(p []byte) (n int, err error) {
+	if x.readMode {
+		panic("blake2b: write to XOF after read")
+	}
+	return x.d.Write(p)
+}
+
+func (x *xof) Clone() XOF {
+	clone := *x
+	return &clone
+}
+
+func (x *xof) Reset() {
+	x.cfg[0] = byte(Size)
+	binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length
+	binary.LittleEndian.PutUint32(x.cfg[12:], x.length)    // XOF length
+	x.cfg[17] = byte(Size)                                 // inner hash size
+
+	x.d.Reset()
+	x.d.h[1] ^= uint64(x.length) << 32
+
+	x.remaining = uint64(x.length)
+	if x.remaining == magicUnknownOutputLength {
+		x.remaining = maxOutputLength
+	}
+	x.offset, x.nodeOffset = 0, 0
+	x.readMode = false
+}
+
+func (x *xof) Read(p []byte) (n int, err error) {
+	if !x.readMode {
+		x.d.finalize(&x.root)
+		x.readMode = true
+	}
+
+	if x.remaining == 0 {
+		return 0, io.EOF
+	}
+
+	n = len(p)
+	if uint64(n) > x.remaining {
+		n = int(x.remaining)
+		p = p[:n]
+	}
+
+	if x.offset > 0 {
+		blockRemaining := Size - x.offset
+		if n < blockRemaining {
+			x.offset += copy(p, x.block[x.offset:])
+			x.remaining -= uint64(n)
+			return
+		}
+		copy(p, x.block[x.offset:])
+		p = p[blockRemaining:]
+		x.offset = 0
+		x.remaining -= uint64(blockRemaining)
+	}
+
+	for len(p) >= Size {
+		binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
+		x.nodeOffset++
+
+		x.d.initConfig(&x.cfg)
+		x.d.Write(x.root[:])
+		x.d.finalize(&x.block)
+
+		copy(p, x.block[:])
+		p = p[Size:]
+		x.remaining -= uint64(Size)
+	}
+
+	if todo := len(p); todo > 0 {
+		if x.remaining < uint64(Size) {
+			x.cfg[0] = byte(x.remaining)
+		}
+		binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
+		x.nodeOffset++
+
+		x.d.initConfig(&x.cfg)
+		x.d.Write(x.root[:])
+		x.d.finalize(&x.block)
+
+		x.offset = copy(p, x.block[:todo])
+		x.remaining -= uint64(todo)
+	}
+	return
+}
+
+func (d *digest) initConfig(cfg *[Size]byte) {
+	d.offset, d.c[0], d.c[1] = 0, 0, 0
+	for i := range d.h {
+		d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(cfg[i*8:])
+	}
+}