podman
1// Copyright 2017 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package blake2b6
7import (8"encoding/binary"9"errors"10"io"11)
12
13// XOF defines the interface to hash functions that
14// support arbitrary-length output.
15type XOF interface {16// Write absorbs more data into the hash's state. It panics if called17// after Read.18io.Writer19
20// Read reads more output from the hash. It returns io.EOF if the limit21// has been reached.22io.Reader23
24// Clone returns a copy of the XOF in its current state.25Clone() XOF26
27// Reset resets the XOF to its initial state.28Reset()29}
30
31// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
32// the length of the output is not known in advance.
33const OutputLengthUnknown = 034
35// magicUnknownOutputLength is a magic value for the output size that indicates
36// an unknown number of output bytes.
37const magicUnknownOutputLength = (1 << 32) - 138
39// maxOutputLength is the absolute maximum number of bytes to produce when the
40// number of output bytes is unknown.
41const maxOutputLength = (1 << 32) * 6442
43// NewXOF creates a new variable-output-length hash. The hash either produce a
44// known number of bytes (1 <= size < 2**32-1), or an unknown number of bytes
45// (size == OutputLengthUnknown). In the latter case, an absolute limit of
46// 256GiB applies.
47//
48// A non-nil key turns the hash into a MAC. The key must between
49// zero and 32 bytes long.
50func NewXOF(size uint32, key []byte) (XOF, error) {51if len(key) > Size {52return nil, errKeySize53}54if size == magicUnknownOutputLength {55// 2^32-1 indicates an unknown number of bytes and thus isn't a56// valid length.57return nil, errors.New("blake2b: XOF length too large")58}59if size == OutputLengthUnknown {60size = magicUnknownOutputLength61}62x := &xof{63d: digest{64size: Size,65keyLen: len(key),66},67length: size,68}69copy(x.d.key[:], key)70x.Reset()71return x, nil72}
73
74type xof struct {75d digest
76length uint3277remaining uint6478cfg, root, block [Size]byte79offset int80nodeOffset uint3281readMode bool82}
83
84func (x *xof) Write(p []byte) (n int, err error) {85if x.readMode {86panic("blake2b: write to XOF after read")87}88return x.d.Write(p)89}
90
91func (x *xof) Clone() XOF {92clone := *x93return &clone94}
95
96func (x *xof) Reset() {97x.cfg[0] = byte(Size)98binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length99binary.LittleEndian.PutUint32(x.cfg[12:], x.length) // XOF length100x.cfg[17] = byte(Size) // inner hash size101
102x.d.Reset()103x.d.h[1] ^= uint64(x.length) << 32104
105x.remaining = uint64(x.length)106if x.remaining == magicUnknownOutputLength {107x.remaining = maxOutputLength108}109x.offset, x.nodeOffset = 0, 0110x.readMode = false111}
112
113func (x *xof) Read(p []byte) (n int, err error) {114if !x.readMode {115x.d.finalize(&x.root)116x.readMode = true117}118
119if x.remaining == 0 {120return 0, io.EOF121}122
123n = len(p)124if uint64(n) > x.remaining {125n = int(x.remaining)126p = p[:n]127}128
129if x.offset > 0 {130blockRemaining := Size - x.offset131if n < blockRemaining {132x.offset += copy(p, x.block[x.offset:])133x.remaining -= uint64(n)134return135}136copy(p, x.block[x.offset:])137p = p[blockRemaining:]138x.offset = 0139x.remaining -= uint64(blockRemaining)140}141
142for len(p) >= Size {143binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)144x.nodeOffset++145
146x.d.initConfig(&x.cfg)147x.d.Write(x.root[:])148x.d.finalize(&x.block)149
150copy(p, x.block[:])151p = p[Size:]152x.remaining -= uint64(Size)153}154
155if todo := len(p); todo > 0 {156if x.remaining < uint64(Size) {157x.cfg[0] = byte(x.remaining)158}159binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)160x.nodeOffset++161
162x.d.initConfig(&x.cfg)163x.d.Write(x.root[:])164x.d.finalize(&x.block)165
166x.offset = copy(p, x.block[:todo])167x.remaining -= uint64(todo)168}169return170}
171
172func (d *digest) initConfig(cfg *[Size]byte) {173d.offset, d.c[0], d.c[1] = 0, 0, 0174for i := range d.h {175d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(cfg[i*8:])176}177}
178