blob: bc12c1fed15775c0a900010a8025248dee263740 [file] [edit]
// Copyright 2020-2025 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package shake256 provides simple utilities around shake256 digests.
package shake256
import (
"fmt"
"io"
"slices"
"golang.org/x/crypto/sha3"
)
const shake256Length = 64
// Digest is a shake256 digest.
type Digest interface {
Value() []byte
isDigest()
}
// NewDigest returns a new Digest for the value.
func NewDigest(value []byte) (Digest, error) {
return newDigest(value)
}
// NewDigestForContent returns a new Digest for the content read from the Reader.
func NewDigestForContent(reader io.Reader) (Digest, error) {
shakeHash := sha3.NewShake256()
// TODO FUTURE: remove in the future, this should have no effect
shakeHash.Reset()
if _, err := io.Copy(shakeHash, reader); err != nil {
return nil, err
}
value := make([]byte, shake256Length)
if _, err := shakeHash.Read(value); err != nil {
// sha3.ShakeHash never errors or short reads. Something horribly wrong
// happened if your computer ended up here.
return nil, err
}
return newDigest(value)
}
// *** PRIVATE ***
type digest struct {
value []byte
}
func newDigest(value []byte) (*digest, error) {
if len(value) != shake256Length {
return nil, fmt.Errorf("invalid shake256 digest value: expected %d bytes, got %d", shake256Length, len(value))
}
return &digest{
value: value,
}, nil
}
func (d *digest) Value() []byte {
return slices.Clone(d.value)
}
func (*digest) isDigest() {}