1// Written in 2012 by Dmitry Chestnykh.
2//
3// To the extent possible under law, the author have dedicated all copyright
4// and related and neighboring rights to this software to the public domain
5// worldwide. This software is distributed without any warranty.
6// http://creativecommons.org/publicdomain/zero/1.0/
7
8// Package blake2b implements BLAKE2b cryptographic hash function.
9package blake2b
10
11import (
12	"encoding/binary"
13	"errors"
14	"hash"
15)
16
17const (
18	BlockSize  = 128 // block size of algorithm
19	Size       = 64  // maximum digest size
20	SaltSize   = 16  // maximum salt size
21	PersonSize = 16  // maximum personalization string size
22	KeySize    = 64  // maximum size of key
23)
24
25type digest struct {
26	h  [8]uint64       // current chain value
27	t  [2]uint64       // message bytes counter
28	f  [2]uint64       // finalization flags
29	x  [BlockSize]byte // buffer for data not yet compressed
30	nx int             // number of bytes in buffer
31
32	ih         [8]uint64       // initial chain value (after config)
33	paddedKey  [BlockSize]byte // copy of key, padded with zeros
34	isKeyed    bool            // indicates whether hash was keyed
35	size       uint8           // digest size in bytes
36	isLastNode bool            // indicates processing of the last node in tree hashing
37}
38
39// Initialization values.
40var iv = [8]uint64{
41	0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
42	0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
43	0x510e527fade682d1, 0x9b05688c2b3e6c1f,
44	0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
45}
46
47// Config is used to configure hash function parameters and keying.
48// All parameters are optional.
49type Config struct {
50	Size   uint8  // digest size (if zero, default size of 64 bytes is used)
51	Key    []byte // key for prefix-MAC
52	Salt   []byte // salt (if < 16 bytes, padded with zeros)
53	Person []byte // personalization (if < 16 bytes, padded with zeros)
54	Tree   *Tree  // parameters for tree hashing
55}
56
57// Tree represents parameters for tree hashing.
58type Tree struct {
59	Fanout        uint8  // fanout
60	MaxDepth      uint8  // maximal depth
61	LeafSize      uint32 // leaf maximal byte length (0 for unlimited)
62	NodeOffset    uint64 // node offset (0 for first, leftmost or leaf)
63	NodeDepth     uint8  // node depth (0 for leaves)
64	InnerHashSize uint8  // inner hash byte length
65	IsLastNode    bool   // indicates processing of the last node of layer
66}
67
68var (
69	defaultConfig = &Config{Size: Size}
70	config256     = &Config{Size: 32}
71)
72
73func verifyConfig(c *Config) error {
74	if c.Size > Size {
75		return errors.New("digest size is too large")
76	}
77	if len(c.Key) > KeySize {
78		return errors.New("key is too large")
79	}
80	if len(c.Salt) > SaltSize {
81		// Smaller salt is okay: it will be padded with zeros.
82		return errors.New("salt is too large")
83	}
84	if len(c.Person) > PersonSize {
85		// Smaller personalization is okay: it will be padded with zeros.
86		return errors.New("personalization is too large")
87	}
88	if c.Tree != nil {
89		if c.Tree.Fanout == 1 {
90			return errors.New("fanout of 1 is not allowed in tree mode")
91		}
92		if c.Tree.MaxDepth < 2 {
93			return errors.New("incorrect tree depth")
94		}
95		if c.Tree.InnerHashSize < 1 || c.Tree.InnerHashSize > Size {
96			return errors.New("incorrect tree inner hash size")
97		}
98	}
99	return nil
100}
101
102// New returns a new hash.Hash configured with the given Config.
103// Config can be nil, in which case the default one is used, calculating 64-byte digest.
104// Returns non-nil error if Config contains invalid parameters.
105func New(c *Config) (hash.Hash, error) {
106	if c == nil {
107		c = defaultConfig
108	} else {
109		if c.Size == 0 {
110			// Set default size if it's zero.
111			c.Size = Size
112		}
113		if err := verifyConfig(c); err != nil {
114			return nil, err
115		}
116	}
117	d := new(digest)
118	d.initialize(c)
119	return d, nil
120}
121
122// initialize initializes digest with the given
123// config, which must be non-nil and verified.
124func (d *digest) initialize(c *Config) {
125	// Create parameter block.
126	var p [BlockSize]byte
127	p[0] = c.Size
128	p[1] = uint8(len(c.Key))
129	if c.Salt != nil {
130		copy(p[32:], c.Salt)
131	}
132	if c.Person != nil {
133		copy(p[48:], c.Person)
134	}
135	if c.Tree != nil {
136		p[2] = c.Tree.Fanout
137		p[3] = c.Tree.MaxDepth
138		binary.LittleEndian.PutUint32(p[4:], c.Tree.LeafSize)
139		binary.LittleEndian.PutUint64(p[8:], c.Tree.NodeOffset)
140		p[16] = c.Tree.NodeDepth
141		p[17] = c.Tree.InnerHashSize
142	} else {
143		p[2] = 1
144		p[3] = 1
145	}
146
147	// Initialize.
148	d.size = c.Size
149	for i := 0; i < 8; i++ {
150		d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(p[i*8:])
151	}
152	if c.Tree != nil && c.Tree.IsLastNode {
153		d.isLastNode = true
154	}
155
156	// Process key.
157	if c.Key != nil {
158		copy(d.paddedKey[:], c.Key)
159		d.Write(d.paddedKey[:])
160		d.isKeyed = true
161	}
162	// Save a copy of initialized state.
163	copy(d.ih[:], d.h[:])
164}
165
166// New512 returns a new hash.Hash computing the BLAKE2b 64-byte checksum.
167func New512() hash.Hash {
168	d := new(digest)
169	d.initialize(defaultConfig)
170	return d
171}
172
173// New256 returns a new hash.Hash computing the BLAKE2b 32-byte checksum.
174func New256() hash.Hash {
175	d := new(digest)
176	d.initialize(config256)
177	return d
178}
179
180// NewMAC returns a new hash.Hash computing BLAKE2b prefix-
181// Message Authentication Code of the given size in bytes
182// (up to 64) with the given key (up to 64 bytes in length).
183func NewMAC(outBytes uint8, key []byte) hash.Hash {
184	d, err := New(&Config{Size: outBytes, Key: key})
185	if err != nil {
186		panic(err.Error())
187	}
188	return d
189}
190
191// Reset resets the state of digest to the initial state
192// after configuration and keying.
193func (d *digest) Reset() {
194	copy(d.h[:], d.ih[:])
195	d.t[0] = 0
196	d.t[1] = 0
197	d.f[0] = 0
198	d.f[1] = 0
199	d.nx = 0
200	if d.isKeyed {
201		d.Write(d.paddedKey[:])
202	}
203}
204
205// Size returns the digest size in bytes.
206func (d *digest) Size() int { return int(d.size) }
207
208// BlockSize returns the algorithm block size in bytes.
209func (d *digest) BlockSize() int { return BlockSize }
210
211func (d *digest) Write(p []byte) (nn int, err error) {
212	nn = len(p)
213	left := BlockSize - d.nx
214	if len(p) > left {
215		// Process buffer.
216		copy(d.x[d.nx:], p[:left])
217		p = p[left:]
218		compress(d, d.x[:])
219		d.nx = 0
220	}
221	// Process full blocks except for the last one.
222	if len(p) > BlockSize {
223		n := len(p) &^ (BlockSize - 1)
224		if n == len(p) {
225			n -= BlockSize
226		}
227		compress(d, p[:n])
228		p = p[n:]
229	}
230	// Fill buffer.
231	d.nx += copy(d.x[d.nx:], p)
232	return
233}
234
235// Sum returns the calculated checksum.
236func (d *digest) Sum(in []byte) []byte {
237	// Make a copy of d so that caller can keep writing and summing.
238	d0 := *d
239	hash := d0.checkSum()
240	return append(in, hash[:d0.size]...)
241}
242
243func (d *digest) checkSum() [Size]byte {
244	// Do not create unnecessary copies of the key.
245	if d.isKeyed {
246		for i := 0; i < len(d.paddedKey); i++ {
247			d.paddedKey[i] = 0
248		}
249	}
250
251	dec := BlockSize - uint64(d.nx)
252	if d.t[0] < dec {
253		d.t[1]--
254	}
255	d.t[0] -= dec
256
257	// Pad buffer with zeros.
258	for i := d.nx; i < len(d.x); i++ {
259		d.x[i] = 0
260	}
261	// Set last block flag.
262	d.f[0] = 0xffffffffffffffff
263	if d.isLastNode {
264		d.f[1] = 0xffffffffffffffff
265	}
266	// Compress last block.
267	compress(d, d.x[:])
268
269	var out [Size]byte
270	j := 0
271	for _, s := range d.h[:(d.size-1)/8+1] {
272		out[j+0] = byte(s >> 0)
273		out[j+1] = byte(s >> 8)
274		out[j+2] = byte(s >> 16)
275		out[j+3] = byte(s >> 24)
276		out[j+4] = byte(s >> 32)
277		out[j+5] = byte(s >> 40)
278		out[j+6] = byte(s >> 48)
279		out[j+7] = byte(s >> 56)
280		j += 8
281	}
282	return out
283}
284
285// Sum512 returns a 64-byte BLAKE2b hash of data.
286func Sum512(data []byte) [64]byte {
287	var d digest
288	d.initialize(defaultConfig)
289	d.Write(data)
290	return d.checkSum()
291}
292
293// Sum256 returns a 32-byte BLAKE2b hash of data.
294func Sum256(data []byte) (out [32]byte) {
295	var d digest
296	d.initialize(config256)
297	d.Write(data)
298	sum := d.checkSum()
299	copy(out[:], sum[:32])
300	return
301}
302