Skip to content

Latest commit

Β 

History

870 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Dynamic SSZ

Go Reference Fuzzing codecov OpenSSF Scorecard Latest Release Go Version License

Dynamic SSZ is a production-ready Go library for SSZ serialization, hashing, and Merkle proofs. Its distinguishing feature is support for runtime-determined field sizes: the same Go types work across different network presets (mainnet, minimal, custom testnets) by resolving size limits from a spec configuration at runtime. It combines instant reflection-based processing for flexibility with optional static code generation for maximum performance.

Features

Encoding, Decoding & Hashing

  • πŸ”§ Dynamic Field Sizes β€” dynssz-size/dynssz-max tags resolve limits from runtime spec values, with full math expression support (e.g. (EPOCHS_PER_HISTORICAL_VECTOR*SLOTS_PER_EPOCH)/8)
  • ⚑ Reflection-Based Processing β€” works instantly with any SSZ-compatible type, no code generation required
  • πŸ—οΈ Code Generation β€” static SSZ methods via the dynssz-gen CLI or programmatic API (2-3x faster than reflection), configurable through flags or YAML config files
  • πŸ“‘ Streaming Support β€” memory-efficient encoding/decoding directly to/from io.Reader/io.Writer for large objects
  • 🌲 Accelerated Hashing β€” SIMD-accelerated hash tree roots via hashtree bindings, with a pure-Go fallback (nohashtree build tag)
  • πŸ”„ fastssz Hybrid β€” automatically delegates to existing fastssz methods where types have no dynamic sizing, for optimal efficiency

Beyond Serialization

  • 🌳 Merkle Proofs β€” build full Merkle trees from any type (GetTree), generate single proofs and compressed multiproofs by generalized index, and verify them with the treeproof package
  • πŸ‘οΈ SSZ Views β€” apply multiple SSZ schemas to the same runtime type without duplicating structs (ideal for Ethereum fork handling)
  • 🎁 Type Wrapper β€” attach SSZ annotations to non-struct top-level types like TypeWrapper[Descriptor, []uint64]

Type System

  • πŸ“š Complete SSZ Type Support β€” vectors, lists, containers, bitvectors/bitlists (ssz-bitsize), uint128/uint256, multi-dimensional arrays with per-dimension limits, time.Time, and auto-detection of common types (holiman/uint256, go-bitfield)
  • πŸš€ Progressive Types β€” progressive lists & bitlists (EIP-7916) and progressive containers with ssz-index (EIP-7495)
  • 🧬 Unions β€” type-safe SSZ unions via the generic Union[T] (classic spec, incl. the None option) and CompatibleUnion[T] (EIP-8016) types
  • 🧩 Extended Types β€” opt-in support for signed integers, floats, big.Int, and optional types (non-standard, disabled by default)

Quality

  • βœ… Spec Compliant β€” validated against the official Ethereum consensus spec tests
  • πŸ§ͺ Differential Fuzzing β€” continuous fuzzing compares reflection and generated code across marshal, unmarshal, hash tree root, and streaming paths
  • πŸ“¦ Minimal Dependencies β€” small dependency footprint, Go 1.22+

Production Readiness

Both processing paths are production ready. The reflection-based code is battle-tested across various Ethereum tooling, and the code generator is feature complete and continuously verified through differential fuzzing against the reflection implementation and the consensus spec tests.

Versioning & Stability

The library follows semantic versioning: breaking changes only occur across major versions, bigger features land in minor versions, and patch versions contain bugfixes and small improvements. Within the same major version, the public API and the behavior of generated code remain backward compatible β€” code generated by every previous v1.x release is archived in codegen/compat-tests and actively checked by the CI on every change. See the security policy for supported versions and vulnerability reporting.

Quick Start

Installation

go get github.com/pk910/dynamic-ssz

Basic Usage

import dynssz "github.com/pk910/dynamic-ssz"

// Define your types with SSZ tags
type MyStruct struct {
    FixedArray  [32]byte
    DynamicList []uint64 `ssz-max:"1000"`
    ConfigBased []byte   `ssz-max:"1024" dynssz-max:"MAX_SIZE"`
}

// Create a DynSsz instance with your configuration
specs := map[string]any{
    "MAX_SIZE": uint64(2048),
}
ds := dynssz.NewDynSsz(specs)

// Marshal
data, err := ds.MarshalSSZ(myObject)

// Unmarshal
err = ds.UnmarshalSSZ(&myObject, data)

// Hash Tree Root
root, err := ds.HashTreeRoot(myObject)

// Merkle tree & proofs
tree, err := ds.GetTree(myObject)
proof, err := tree.Prove(generalizedIndex)

The ssz-max and dynssz-max tags work together: ssz-max provides a static fallback, while dynssz-max references a spec value resolved at runtime. If the spec value is available it overrides the static default; otherwise the static value is used. This lets the same types work across different network presets (mainnet, minimal, custom testnets).

Using Code Generation (Recommended for Production)

For maximum performance, use code generation with the dynssz-gen CLI tool:

go install github.com/pk910/dynamic-ssz/dynssz-gen@latest

Generate SSZ methods:

# Generate for types in current package
dynssz-gen -package . -types "MyStruct,OtherType" -output generated.go

# Generate for types in external package
dynssz-gen -package github.com/example/types -types "Block" -output block_ssz.go

# Or drive everything from a YAML config file
dynssz-gen -config dynssz.yaml

Generated code produces optimized SSZ methods that eliminate reflection overhead. Important: Always use ds.MarshalSSZ(), ds.UnmarshalSSZ(), etc. as your entry points - the runtime automatically delegates to generated methods when available. Do not call generated methods (like MarshalSSZDyn) directly, as this creates a circular dependency that prevents regeneration. See the Code Generation Guide for details.

Performance

Dynamic SSZ is benchmarked against other SSZ libraries (including fastssz) in a dedicated benchmark repository: pk910/ssz-benchmark (view graphs).

SSZ Benchmark Results

The benchmarks compare encoding, decoding, and hash tree root performance across different SSZ libraries using common Ethereum consensus data structures.

View interactive benchmark results and historical trends at: https://pk910.github.io/ssz-benchmark/

Testing

The library includes comprehensive testing infrastructure:

  • Unit Tests: Fast, isolated tests for core functionality
  • Spec Tests: Ethereum consensus specification compliance tests
  • Fuzz Testing: Continuous fuzzing via CI that generates random SSZ type structures and verifies correctness by comparing reflection and codegen implementations across marshal, unmarshal, hash tree root, and streaming operations
  • Examples: Working examples that are automatically tested
  • Performance Tests: Benchmarking and regression testing
  • Static Analysis: golangci-lint and CodeQL scanning on every change

Documentation

Examples

Check out the examples directory for standalone, CI-tested example projects:

  • basic β€” simple encoding/decoding with Ethereum consensus types
  • chain-specs β€” preset-aware serialization: load a chain config and serialize the same types under mainnet, minimal, or custom devnet presets
  • codegen β€” code generation setup with a programmatic generator
  • custom-types β€” custom specifications and dynamic expressions
  • fork-views β€” one fork-agnostic type with per-fork SSZ schemas via views, plus view-only code generation
  • htr-caching β€” application-level hash-tree-root caching on a large validator registry via the DynamicHashRoot delegation hook
  • merkle-proofs β€” Merkle tree construction, generalized-index proofs into nested lists, multiproofs and standalone verification
  • progressive-merkleization β€” progressive lists, bitlists, and containers (EIP-7916/EIP-7495)
  • streaming β€” stream SSZ to/from files and network connections without buffering the full payload
  • versioned-blocks β€” handling Ethereum fork-versioned block structures

Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

License

Dynamic SSZ is licensed under the Apache 2.0 License.

About

Dynamic SSZ serializer in go

Topics

Resources

Contributing

Security policy

Stars

23 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages