hasher

package
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2026 License: Apache-2.0 Imports: 10 Imported by: 4

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DisableAsyncHashing added in v1.4.0

func DisableAsyncHashing()

DisableAsyncHashing turns background subtree reduction off. Reductions already in flight complete independently; only new work is affected.

func EnableAsyncHashing added in v1.4.0

func EnableAsyncHashing(workers int)

EnableAsyncHashing enables background subtree reduction for all hashers whose hash function is safe for concurrent use (hashers created via NewHasherWithHashFn, including the FastHasherPool). At most workers reductions run concurrently, and job input memory is bounded by twice workers pre-sized buffers. workers <= 0 disables async hashing.

Roots are unaffected: async and synchronous hashing produce identical results. Peak buffer usage grows by up to a few megabytes per hasher because deferred subtrees accumulate into wider runs before reduction.

func GetZeroHash added in v1.1.1

func GetZeroHash(depth int) []byte

GetZeroHash returns a copy of the precomputed zero hash at the given merkle tree depth; the caller owns it. Depths outside the supported range are clamped to the nearest valid level.

func GetZeroHashLevel added in v1.1.1

func GetZeroHashLevel(hash string) (int, bool)

GetZeroHashLevel returns the merkle tree depth level for a known zero hash. Returns the level and true if the hash is a recognized zero hash, or 0 and false otherwise.

func GetZeroHashLevelBytes added in v1.3.0

func GetZeroHashLevelBytes(hash []byte) (int, bool)

GetZeroHashLevelBytes returns the merkle tree depth level for a known zero hash. Returns the level and true if the hash is a recognized zero hash, or 0 and false otherwise.

func GetZeroHashes added in v1.1.1

func GetZeroHashes() [65][32]byte

GetZeroHashes returns the full array of precomputed zero hashes for all 65 merkle tree depth levels.

func ParseBitlist

func ParseBitlist(dst, buf []byte) ([]byte, uint64)

ParseBitlist decodes an SSZ-encoded bitlist into its raw bit representation.

SSZ bitlists include a mandatory termination bit: a single `1` bit appended immediately after the final data bit, then padded to a full byte. The position of this termination bit defines the logical length of the bitlist.

This function performs the inverse transformation:

  1. Identify the termination bit in the final byte and compute the logical bitlist length (`size`).
  2. Clear the termination bit, leaving only the actual data bits.
  3. Trim any trailing zero bytes introduced by SSZ padding.
  4. Return the compact raw bitlist (no termination bit, no padding) together with its logical size.

The returned `[]byte` contains the data bits packed little-endian in each byte, and `size` is the exact number of meaningful bits in that raw bitlist.

func ParseBitlistWithHasher added in v1.2.0

func ParseBitlistWithHasher(hw sszutils.HashWalker, buf []byte) ([]byte, uint64)

ParseBitlistWithHasher decodes an SSZ-encoded bitlist using the hasher's internal buffer to avoid allocations. It returns the raw bit data and the logical bit count, same as ParseBitlist.

IMPORTANT: The returned bitlist slice references the hasher's internal buffer spare capacity. It must be consumed (e.g. passed to AppendBytes32) before any operation that may grow the buffer, as a reallocation would invalidate it.

func ParseProgressiveBitlist added in v1.3.2

func ParseProgressiveBitlist(dst, buf []byte) ([]byte, uint64)

ParseProgressiveBitlist decodes an SSZ-encoded bitlist for progressive merkleization.

It behaves like ParseBitlist (strips the termination bit and returns the logical bit count), but instead of trimming trailing zero bytes it zero-pads the content to exactly ceil(size/256) 256-bit chunks (ceil(size/256)*32 bytes).

This distinction is essential: progressive merkleization derives the tree structure from the chunk count (subtree_fill_progressive recurses by chunk index), so an all-zero top chunk must be preserved. ParseBitlist's trimming is harmless for regular bitlists because they pad to a fixed chunk limit, but it would silently drop top chunks here and produce a wrong root.

func ParseProgressiveBitlistWithHasher added in v1.3.2

func ParseProgressiveBitlistWithHasher(hw sszutils.HashWalker, buf []byte) ([]byte, uint64)

ParseProgressiveBitlistWithHasher decodes an SSZ-encoded bitlist for progressive merkleization using the hasher's internal buffer to avoid allocations. It returns the chunk-aligned, untrimmed bit data and the logical bit count, same as ParseProgressiveBitlist.

IMPORTANT: The returned bitlist slice references the hasher's internal buffer spare capacity. It must be consumed (e.g. passed to AppendBytes32) before any operation that may grow the buffer, as a reallocation would invalidate it.

func WithDefaultHasher added in v1.1.1

func WithDefaultHasher(fn func(hh sszutils.HashWalker) error) error

WithDefaultHasher acquires a Hasher from the FastHasherPool, passes it to fn, and returns it to the pool when done. This is a convenience wrapper for one-off hashing operations.

Types

type HashFn

type HashFn func(dst []byte, input []byte) error

HashFn is a function that hashes pairs of 32-byte chunks from input into dst. It processes the input as consecutive 64-byte pairs and writes each 32-byte hash result into dst.

func NativeHashWrapper

func NativeHashWrapper(hashFn hash.Hash) HashFn

NativeHashWrapper wraps a hash.Hash instance into a HashFn. The instance is stateful, so the returned function is NOT safe for concurrent use and the hasher carrying it must stay gated out of async hashing; use NativeHashWrapperFactory when that is needed.

func NativeHashWrapperFactory added in v1.4.0

func NativeHashWrapperFactory(newHash func() hash.Hash) HashFn

NativeHashWrapperFactory wraps a hash.Hash constructor into a HashFn that is safe for concurrent use: every call draws its own instance from a pool. This is what makes the native-hash path eligible for async hashing.

type Hasher

type Hasher struct {
	// contains filtered or unexported fields
}

Hasher is a utility tool to hash SSZ structs

func NewHasher

func NewHasher() *Hasher

NewHasher creates a new Hasher with the default sha256 hash function. The hash function draws per-call instances from a pool, so the hasher may be gated into async hashing.

It takes the built-in compression whatever FastHasherPool holds, so a caller who installed a backend there names it here too, with NewHasherWithHashFn, or draws the hasher from the pool with Get. A tree built by treeproof.NewWrapper reads the pool instead, so the two answer differently for the same value while only one of them is told.

func NewHasherWithHash

func NewHasherWithHash(hh hash.Hash) *Hasher

NewHasherWithHash creates a new Hasher with a custom hash.Hash function. hash.Hash instances are stateful and not safe for concurrent use, so such a hasher must not be gated into async hashing (see SetAsyncHashing).

func NewHasherWithHashFn

func NewHasherWithHashFn(hh HashFn) *Hasher

NewHasherWithHashFn creates a new Hasher with a custom HashFn function.

func (*Hasher) Append

func (h *Hasher) Append(i []byte)

Append appends raw bytes to the buffer without padding.

func (*Hasher) AppendBool

func (h *Hasher) AppendBool(b bool)

AppendBool appends a single byte (0 or 1) to the buffer without padding.

func (*Hasher) AppendBytes32

func (h *Hasher) AppendBytes32(b []byte)

AppendBytes32 appends b to the buffer, right-padding with zeros so the value occupies a whole number of chunks counted from where it begins. Chunks are always counted from the start of what is being built -- the value here, the region in fillRegionUpTo32 -- which is how the SSZ spec defines them and what keeps every region a whole number of chunks.

func (*Hasher) AppendUint8

func (h *Hasher) AppendUint8(i uint8)

AppendUint8 appends a uint8 to the buffer without padding.

func (*Hasher) AppendUint16

func (h *Hasher) AppendUint16(i uint16)

AppendUint16 appends a little-endian uint16 to the buffer without padding.

func (*Hasher) AppendUint32

func (h *Hasher) AppendUint32(i uint32)

AppendUint32 appends a little-endian uint32 to the buffer without padding.

func (*Hasher) AppendUint64

func (h *Hasher) AppendUint64(i uint64)

AppendUint64 appends a little-endian uint64 to the buffer without padding.

func (*Hasher) Collapse added in v1.3.0

func (h *Hasher) Collapse()

Collapse hints the hasher to collapse accumulated chunks in the current layer if the batch threshold is reached. This is a no-op for non-incremental layers or when no layer is active.

The hint is optional and never changes a root, whatever the scope holds: a scope over its limit reduces at the depth its chunks need either way. The one shape it could move -- a scope opened progressive and reduced as binary, where the hint decides whether progressive groups or raw chunks are reduced -- is refused instead, through ErrScopeShapeMismatch.

func (*Hasher) CurrentIndex added in v1.3.0

func (h *Hasher) CurrentIndex() int

CurrentIndex returns the current buffer position without pushing a layer.

func (*Hasher) FillUpTo32

func (h *Hasher) FillUpTo32()

FillUpTo32 pads the buffer with zero bytes to the next chunk boundary of the buffer. Callers use it after a value that has to occupy whole chunks; a reduction pads its own region through fillRegionUpTo32 and needs no call.

func (*Hasher) Hash

func (h *Hasher) Hash() []byte

Hash returns the last 32 bytes of the buffer, flushing pending deferred chunks first so the tail holds the latest merkleize result. Outstanding background reductions are awaited only when their hole can overlap the tail; holes below it are left to fill in the background. The returned slice is only valid until the next hasher operation.

The flush performs the scope's reduction, so the backend can refuse it here and at no earlier call: the tail is a root only while HashErr, read after Hash, is nil.

func (*Hasher) HashErr added in v1.4.0

func (h *Hasher) HashErr() error

HashErr reports the first error a hash function returned for this hasher, or nil. A failed hash leaves the bytes it would have written untouched, so a caller reading the buffer -- through Hash, or by caching a scope root -- takes a value that was never produced. HashRoot reports the same error, but a walk that ends without asking for the root has nothing else to consult.

func (*Hasher) HashRoot

func (h *Hasher) HashRoot() (res [32]byte, err error)

HashRoot returns the final 32-byte hash root, or an error if a hash function failed, scopes are still open, or the buffer is not exactly 32 bytes. Outstanding background reductions are drained first so no unfilled hole can be exposed and a failure inside one is seen here — with async hashing, a buffer of the right length is not otherwise evidence of a finished computation.

func (*Hasher) Index

func (h *Hasher) Index() int

Index returns the current buffer position and pushes a non-incremental layer that is reduced in place when it closes and never deferred into the enclosing scope. This is how legacy/external code (fastssz-generated methods) opens scopes: after Merkleize the region holds the scope's root, so a caller may mix further chunks into it and reduce it again. Unlike StartTree, no pending flush is forced on the enclosing scope.

func (*Hasher) Merkleize

func (h *Hasher) Merkleize(indx int)

Merkleize computes the binary merkle root of the buffer from indx onwards and replaces that region with the 32-byte root. Pops the matching layer if one exists.

func (*Hasher) MerkleizeProgressive

func (h *Hasher) MerkleizeProgressive(indx int)

MerkleizeProgressive computes the progressive merkle root of the buffer from indx onwards. If incremental progressive data was accumulated via Collapse, it is finalized; otherwise the standard recursive algorithm is used.

func (*Hasher) MerkleizeProgressiveWithActiveFields

func (h *Hasher) MerkleizeProgressiveWithActiveFields(indx int, activeFields []byte)

MerkleizeProgressiveWithActiveFields computes the progressive merkle root from indx and mixes in the active fields bitvector.

func (*Hasher) MerkleizeProgressiveWithMixin

func (h *Hasher) MerkleizeProgressiveWithMixin(indx int, num uint64)

MerkleizeProgressiveWithMixin computes the progressive merkle root from indx and mixes in num as the list length.

func (*Hasher) MerkleizeWithMixin

func (h *Hasher) MerkleizeWithMixin(indx int, num, limit uint64)

MerkleizeWithMixin computes the binary merkle root from indx with the given limit, then mixes in num as the list length. Pops the matching layer if one exists. A scope holding more chunks than the limit allows is reduced at the depth its chunks need, so every chunk reaches the root: both engines reject an over-capacity value before this point, so the surplus can only come from a hash method leaving more than one leaf per value.

func (*Hasher) PutBitlist

func (h *Hasher) PutBitlist(bb []byte, maxSize uint64)

PutBitlist appends an SSZ-encoded bitlist, merkleizes its content, and mixes in the bit count with the given maxSize limit.

func (*Hasher) PutBool

func (h *Hasher) PutBool(b bool)

PutBool appends a boolean as a 32-byte zero-padded chunk, or as one packed byte inside a packed scope.

func (*Hasher) PutBytes

func (h *Hasher) PutBytes(b []byte)

PutBytes appends b as a 32-byte chunk, or as its raw bytes inside a packed scope. If b exceeds 32 bytes, the content is merkleized in-place to a single root without interacting with the layer stack.

func (*Hasher) PutProgressiveBitlist

func (h *Hasher) PutProgressiveBitlist(bb []byte)

PutProgressiveBitlist appends an SSZ-encoded bitlist and merkleizes it using the progressive algorithm with a length mixin.

func (*Hasher) PutRootVector

func (h *Hasher) PutRootVector(b [][]byte, maxCapacity ...uint64) error

PutRootVector appends an array of 32-byte roots and merkleizes them. If maxCapacity is provided, the result includes a length mixin.

func (*Hasher) PutUint8

func (h *Hasher) PutUint8(i uint8)

PutUint8 appends a uint8 as a 32-byte zero-padded chunk, or as one packed byte inside a packed scope.

func (*Hasher) PutUint16

func (h *Hasher) PutUint16(i uint16)

PutUint16 appends a little-endian uint16 as a 32-byte zero-padded chunk, or as its 2 packed bytes inside a packed scope.

func (*Hasher) PutUint32

func (h *Hasher) PutUint32(i uint32)

PutUint32 appends a little-endian uint32 as a 32-byte zero-padded chunk, or as its 4 packed bytes inside a packed scope.

func (*Hasher) PutUint64

func (h *Hasher) PutUint64(i uint64)

PutUint64 appends a little-endian uint64 as a 32-byte zero-padded chunk, or as its 8 packed bytes inside a packed scope.

func (*Hasher) PutUint64Array

func (h *Hasher) PutUint64Array(b []uint64, maxCapacity ...uint64)

PutUint64Array appends an array of uint64 values and merkleizes them. If maxCapacity is provided, the result includes a length mixin.

func (*Hasher) Reset

func (h *Hasher) Reset()

Reset clears the buffer, layer stack, hash error and async gate for reuse. Outstanding background reductions are awaited and their results discarded.

func (*Hasher) SetAsyncHashing added in v1.4.0

func (h *Hasher) SetAsyncHashing(enabled bool)

SetAsyncHashing gates this hasher into (or out of) background subtree reduction. It only takes effect while async hashing is enabled process-wide via EnableAsyncHashing. The hash function must be safe for concurrent use — background goroutines call it alongside the walker. NewHasher and the pooled hashers qualify; a hasher wrapping a single stateful hash.Hash (NewHasherWithHash) must stay gated out. Reset clears the gate, so pool users re-apply it per acquisition.

func (*Hasher) StartTree added in v1.3.0

func (h *Hasher) StartTree(treeType sszutils.TreeType) int

StartTree opens a new SSZ object scope and returns the buffer index. TreeTypeBinary/Progressive: pushes an incremental layer (supports Collapse). TreeTypeNone: pushes a non-incremental layer (Collapse is a no-op on this scope).

func (*Hasher) WithTemp

func (h *Hasher) WithTemp(fn func(tmp []byte) []byte)

WithTemp provides access to the hasher's temporary buffer via a callback. The callback receives the tmp buffer and must return a (possibly reallocated) replacement.

type HasherPool

type HasherPool struct {
	HashFn HashFn
	// contains filtered or unexported fields
}

HasherPool may be used for pooling Hashers for similarly typed SSZs.

var DefaultHasherPool HasherPool

DefaultHasherPool is a default hasher pool

var FastHasherPool HasherPool = HasherPool{
	HashFn: hashtree.HashByteSlice,
}

FastHasherPool is the fast hasher pool that uses the hashtree library if cgo is enabled

func (*HasherPool) CurrentHashFn added in v1.4.0

func (hh *HasherPool) CurrentHashFn() HashFn

CurrentHashFn reports the function the pool hands its hashers, which is the built-in when none was installed. Callers that hash outside a pooled Hasher use it so they compress with the same function a root does.

func (*HasherPool) Get

func (hh *HasherPool) Get() *Hasher

Get acquires a Hasher from the pool.

func (*HasherPool) Put

func (hh *HasherPool) Put(h *Hasher)

Put releases the Hasher to the pool.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL