1// Copyright 2014 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 sha3
6
7// This file defines the ShakeHash interface, and provides
8// functions for creating SHAKE and cSHAKE instances, as well as utility
9// functions for hashing bytes to arbitrary-length output.
10//
11//
12// SHAKE implementation is based on FIPS PUB 202 [1]
13// cSHAKE implementations is based on NIST SP 800-185 [2]
14//
15// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
16// [2] https://doi.org/10.6028/NIST.SP.800-185
17
18import (
19	"encoding/binary"
20	"hash"
21	"io"
22)
23
24// ShakeHash defines the interface to hash functions that support
25// arbitrary-length output. When used as a plain [hash.Hash], it
26// produces minimum-length outputs that provide full-strength generic
27// security.
28type ShakeHash interface {
29	hash.Hash
30
31	// Read reads more output from the hash; reading affects the hash's
32	// state. (ShakeHash.Read is thus very different from Hash.Sum)
33	// It never returns an error, but subsequent calls to Write or Sum
34	// will panic.
35	io.Reader
36
37	// Clone returns a copy of the ShakeHash in its current state.
38	Clone() ShakeHash
39}
40
41// cSHAKE specific context
42type cshakeState struct {
43	*state // SHA-3 state context and Read/Write operations
44
45	// initBlock is the cSHAKE specific initialization set of bytes. It is initialized
46	// by newCShake function and stores concatenation of N followed by S, encoded
47	// by the method specified in 3.3 of [1].
48	// It is stored here in order for Reset() to be able to put context into
49	// initial state.
50	initBlock []byte
51}
52
53// Consts for configuring initial SHA-3 state
54const (
55	dsbyteShake  = 0x1f
56	dsbyteCShake = 0x04
57	rate128      = 168
58	rate256      = 136
59)
60
61func bytepad(input []byte, w int) []byte {
62	// leftEncode always returns max 9 bytes
63	buf := make([]byte, 0, 9+len(input)+w)
64	buf = append(buf, leftEncode(uint64(w))...)
65	buf = append(buf, input...)
66	padlen := w - (len(buf) % w)
67	return append(buf, make([]byte, padlen)...)
68}
69
70func leftEncode(value uint64) []byte {
71	var b [9]byte
72	binary.BigEndian.PutUint64(b[1:], value)
73	// Trim all but last leading zero bytes
74	i := byte(1)
75	for i < 8 && b[i] == 0 {
76		i++
77	}
78	// Prepend number of encoded bytes
79	b[i-1] = 9 - i
80	return b[i-1:]
81}
82
83func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash {
84	c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}}
85
86	// leftEncode returns max 9 bytes
87	c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
88	c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...)
89	c.initBlock = append(c.initBlock, N...)
90	c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...)
91	c.initBlock = append(c.initBlock, S...)
92	c.Write(bytepad(c.initBlock, c.rate))
93	return &c
94}
95
96// Reset resets the hash to initial state.
97func (c *cshakeState) Reset() {
98	c.state.Reset()
99	c.Write(bytepad(c.initBlock, c.rate))
100}
101
102// Clone returns copy of a cSHAKE context within its current state.
103func (c *cshakeState) Clone() ShakeHash {
104	b := make([]byte, len(c.initBlock))
105	copy(b, c.initBlock)
106	return &cshakeState{state: c.clone(), initBlock: b}
107}
108
109// Clone returns copy of SHAKE context within its current state.
110func (c *state) Clone() ShakeHash {
111	return c.clone()
112}
113
114// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
115// Its generic security strength is 128 bits against all attacks if at
116// least 32 bytes of its output are used.
117func NewShake128() ShakeHash {
118	return newShake128()
119}
120
121// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
122// Its generic security strength is 256 bits against all attacks if
123// at least 64 bytes of its output are used.
124func NewShake256() ShakeHash {
125	return newShake256()
126}
127
128func newShake128Generic() *state {
129	return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake}
130}
131
132func newShake256Generic() *state {
133	return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake}
134}
135
136// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
137// a customizable variant of SHAKE128.
138// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
139// desired. S is a customization byte string used for domain separation - two cSHAKE
140// computations on same input with different S yield unrelated outputs.
141// When N and S are both empty, this is equivalent to NewShake128.
142func NewCShake128(N, S []byte) ShakeHash {
143	if len(N) == 0 && len(S) == 0 {
144		return NewShake128()
145	}
146	return newCShake(N, S, rate128, 32, dsbyteCShake)
147}
148
149// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
150// a customizable variant of SHAKE256.
151// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
152// desired. S is a customization byte string used for domain separation - two cSHAKE
153// computations on same input with different S yield unrelated outputs.
154// When N and S are both empty, this is equivalent to NewShake256.
155func NewCShake256(N, S []byte) ShakeHash {
156	if len(N) == 0 && len(S) == 0 {
157		return NewShake256()
158	}
159	return newCShake(N, S, rate256, 64, dsbyteCShake)
160}
161
162// ShakeSum128 writes an arbitrary-length digest of data into hash.
163func ShakeSum128(hash, data []byte) {
164	h := NewShake128()
165	h.Write(data)
166	h.Read(hash)
167}
168
169// ShakeSum256 writes an arbitrary-length digest of data into hash.
170func ShakeSum256(hash, data []byte) {
171	h := NewShake256()
172	h.Write(data)
173	h.Read(hash)
174}
175