Files
zeekay d387380237 blake3: vanilla Go canonical (closes hard violation #3)
Author lux/crypto/blake3/ to mirror lux/crypto/keccak and lux/crypto/sha256:

- blake3.go: Hash, HashHex, HashBatch, New, NewKeyed, KeyedHash,
  DeriveKey, Reader (XOF), Concat. Backed by github.com/zeebo/blake3
  (BSD-3, pure Go with SSE4.1/AVX2/NEON), counted as vanilla per
  CANONICAL_AUDIT.md directive.
- gpu.go: batchGPU stub matching keccak/sha256 dispatch surface; falls
  through to CPU because luxfi/accel does not yet expose a real BLAKE3
  kernel (its HashBlake3 currently aliases SHA-256). When accel ships
  the kernel, wire it in here, no API change.
- blake3_test.go: 35/35 official BLAKE3 reference KAT vectors
  (test_vectors.json embedded) for hash, keyed_hash, derive_key. Plus
  batch parity, incremental==contiguous, XOF, hex, key-size validation.
- doc.go: package overview matching keccak/sha256 docs.

Closes the blake3 hard violation in CANONICAL_AUDIT.md (commit dbd728c).
2025-12-28 05:29:26 -08:00

121 lines
3.1 KiB
Go

// Copyright (C) 2020-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package blake3
import (
"hash"
"io"
"github.com/zeebo/blake3"
)
// Size is the default output size of BLAKE3 in bytes.
const Size = 32
// KeySize is the required key length for the keyed-hash mode.
const KeySize = 32
// BatchThreshold is the minimum batch length at which HashBatch will try to
// route through GPU (lux/accel). Below this threshold the vanilla path is
// always faster (PCIe round-trip dominates).
//
// Tuned to match the keccak/sha256 packages; expose as a knob so downstream
// profilers can override per workload.
var BatchThreshold = 256
// Hash returns the BLAKE3-256 hash of in. Allocations: 1.
func Hash(in []byte) [Size]byte {
return blake3.Sum256(in)
}
// HashHex is a convenience that returns a hex string of Hash(in).
func HashHex(in []byte) string {
h := Hash(in)
const hex = "0123456789abcdef"
out := make([]byte, 2*Size)
for i, b := range h {
out[2*i] = hex[b>>4]
out[2*i+1] = hex[b&0x0f]
}
return string(out)
}
// New returns a hash.Hash computing BLAKE3-256.
//
// Use Hash when you have a contiguous input; New when you need to write
// incrementally.
func New() hash.Hash {
return blake3.New()
}
// NewKeyed returns a hash.Hash computing keyed BLAKE3 (MAC mode).
// key must be exactly KeySize (32) bytes.
func NewKeyed(key []byte) (hash.Hash, error) {
return blake3.NewKeyed(key)
}
// KeyedHash computes keyed BLAKE3 over in with the given 32-byte key.
// Returns an error if the key is not exactly KeySize bytes.
func KeyedHash(key, in []byte) ([Size]byte, error) {
var out [Size]byte
h, err := blake3.NewKeyed(key)
if err != nil {
return out, err
}
h.Write(in)
h.Sum(out[:0])
return out, nil
}
// DeriveKey derives a key of len(out) bytes from material in the given
// hardcoded context (RFC-style KDF mode). Context strings should be
// hardcoded constants per the BLAKE3 spec, e.g.
// "example.com 2026-04-27 session tokens v1".
func DeriveKey(context string, material, out []byte) {
blake3.DeriveKey(context, material, out)
}
// Reader returns an io.Reader yielding the BLAKE3 XOF stream of in. The
// stream is unbounded and seekable.
func Reader(in []byte) io.ReadSeeker {
h := blake3.New()
h.Write(in)
return h.Digest()
}
// Concat returns the BLAKE3-256 hash of the concatenation of all inputs,
// without allocating an intermediate buffer.
func Concat(inputs ...[]byte) [Size]byte {
h := blake3.New()
for _, b := range inputs {
h.Write(b)
}
var out [Size]byte
h.Sum(out[:0])
return out
}
// HashBatch computes BLAKE3-256 for a batch of inputs.
//
// When the batch is large enough and the GPU backend is available the
// computation runs on the GPU; otherwise it runs on the CPU. The output is
// always byte-identical to repeated calls to Hash.
func HashBatch(inputs [][]byte) [][Size]byte {
out := make([][Size]byte, len(inputs))
if len(inputs) == 0 {
return out
}
if len(inputs) >= BatchThreshold {
if ok, err := batchGPU(inputs, out); ok && err == nil {
return out
}
}
for i, in := range inputs {
out[i] = blake3.Sum256(in)
}
return out
}