![]() |
VOOZH | about |
dotnet add package Nethereum.Ssz --version 6.1.0
NuGet\Install-Package Nethereum.Ssz -Version 6.1.0
<PackageReference Include="Nethereum.Ssz" Version="6.1.0" />
<PackageVersion Include="Nethereum.Ssz" Version="6.1.0" />Directory.Packages.props
<PackageReference Include="Nethereum.Ssz" />Project file
paket add Nethereum.Ssz --version 6.1.0
#r "nuget: Nethereum.Ssz, 6.1.0"
#:package Nethereum.Ssz@6.1.0
#addin nuget:?package=Nethereum.Ssz&version=6.1.0Install as a Cake Addin
#tool nuget:?package=Nethereum.Ssz&version=6.1.0Install as a Cake Tool
Minimal Simple Serialize (SSZ) primitives for Ethereum consensus layer serialization and Merkleization.
Nethereum.Ssz provides a lightweight implementation of Simple Serialize (SSZ), the serialization format used by Ethereum's consensus layer (Beacon Chain, validators, light clients):
SSZ is different from RLP (used in execution layer):
dotnet add package Nethereum.Ssz
Nethereum Dependencies:
Simple Serialize (SSZ) is the serialization standard for Ethereum's consensus layer:
| Feature | SSZ (Consensus Layer) | RLP (Execution Layer) |
|---|---|---|
| Encoding | Little-endian | Big-endian (network) |
| Hash Function | SHA-256 | Keccak-256 |
| Type System | Strongly typed | Dynamic |
| Use Case | Consensus, light clients | Transactions, blocks |
Fixed-Size Types:
boolean: 1 byte (0x00 or 0x01)uint8, uint16, uint32, uint64: Little-endian integersBytes[N]: Fixed-length byte arrayVector[N]: Fixed-length homogeneous collectionVariable-Size Types:
List[N]: Variable-length collection (max N elements)Bytes: Variable-length byte arraySSZ defines hash tree roots for all types:
using Nethereum.Ssz;
// Serialize data
using var writer = new SszWriter();
writer.WriteBoolean(true);
writer.WriteUInt64(42);
writer.WriteFixedBytes(new byte[32], 32);
byte[] encoded = writer.ToArray();
// Deserialize data
var reader = new SszReader(encoded);
bool flag = reader.ReadBoolean();
ulong value = reader.ReadUInt64();
byte[] hash = reader.ReadFixedBytes(32);
using Nethereum.Ssz;
// Create fixed-size byte array
var fixedBytes = new byte[32];
fixedBytes[0] = 0xAA;
fixedBytes[31] = 0xBB;
// Write primitives
byte[] buffer;
using (var writer = new SszWriter())
{
writer.WriteBoolean(true); // 1 byte: 0x01
writer.WriteUInt64(42); // 8 bytes: little-endian
writer.WriteFixedBytes(fixedBytes, 32); // 32 bytes
buffer = writer.ToArray();
}
// Read back
var reader = new SszReader(buffer);
bool boolValue = reader.ReadBoolean(); // true
ulong intValue = reader.ReadUInt64(); // 42
byte[] bytes = reader.ReadFixedBytes(32); // original array
Assert.True(boolValue);
Assert.Equal((ulong)42, intValue);
Assert.Equal(fixedBytes, bytes);
Source: tests/Nethereum.Ssz.Tests/SszWriterReaderTests.cs
using Nethereum.Ssz;
// Write variable-length bytes
byte[] buffer;
using (var writer = new SszWriter())
{
var data = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 };
// Length prefix (4 bytes) + data
writer.WriteVariableBytes(data, maxLength: 100);
buffer = writer.ToArray();
}
// Buffer contains: [0x05, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05]
// ^^^^^^^^^^^^^^^^^^^^^^^^^ length prefix (5 in little-endian)
// Read back
var reader = new SszReader(buffer);
byte[] result = reader.ReadVariableBytes(maxLength: 100);
Assert.Equal(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 }, result);
Source: tests/Nethereum.Ssz.Tests/SszWriterReaderTests.cs
using Nethereum.Ssz;
using System.Collections.Generic;
// Write a list of uint64
byte[] buffer;
using (var writer = new SszWriter())
{
var values = new List<ulong> { 10UL, 12UL, 99UL };
writer.WriteList(
values,
(w, value) => w.WriteUInt64(value), // Element writer
maxLength: 100 // Max list size
);
buffer = writer.ToArray();
}
// Read back (need to know count)
var reader = new SszReader(buffer);
ulong[] result = SszReader.ReadList<ulong>(ref reader, count: 3);
Assert.Equal(new[] { 10UL, 12UL, 99UL }, result);
Source: tests/Nethereum.Ssz.Tests/SszWriterReaderTests.cs
using Nethereum.Ssz;
using System.Collections.Generic;
// Vector: fixed number of fixed-size elements
using var writer = new SszWriter();
var vector = new List<byte[]>
{
Enumerable.Repeat((byte)0x11, 32).ToArray(),
Enumerable.Repeat((byte)0x22, 32).ToArray(),
Enumerable.Repeat((byte)0x33, 32).ToArray()
};
// Write vector (validates count matches expected)
writer.WriteVector(
vector,
elementSize: 32,
expectedElementCount: 3
);
byte[] encoded = writer.ToArray();
// encoded.Length = 96 bytes (3 × 32)
// Read back
var reader = new SszReader(encoded);
byte[][] result = reader.ReadVector(elementCount: 3, elementSize: 32);
Assert.Equal(vector, result);
Source: tests/Nethereum.Ssz.Tests/SszWriterReaderTests.cs and src/Nethereum.Ssz/SszReader.cs
using Nethereum.Ssz;
using System.Collections.Generic;
using System.Linq;
// Create two 32-byte chunks
var chunkA = Enumerable.Repeat((byte)0x11, 32).ToArray();
var chunkB = Enumerable.Repeat((byte)0x22, 32).ToArray();
var chunks = new List<byte[]> { chunkA, chunkB };
// Compute Merkle root
byte[] root = SszMerkleizer.Merkleize(chunks);
// root = SHA256(chunkA || chunkB)
// Result is a 32-byte hash
// Verify against manual SHA-256
using (var sha = System.Security.Cryptography.SHA256.Create())
{
var concat = new byte[64];
Buffer.BlockCopy(chunkA, 0, concat, 0, 32);
Buffer.BlockCopy(chunkB, 0, concat, 32, 32);
var expected = sha.ComputeHash(concat);
Assert.Equal(expected, root);
}
Source: tests/Nethereum.Ssz.Tests/SszMerkleizerTests.cs
using Nethereum.Ssz;
using System.Linq;
// Data that doesn't align to 32-byte chunks
var data = Enumerable.Range(0, 40).Select(i => (byte)i).ToArray();
// Split into 32-byte chunks (pads last chunk with zeros)
var chunks = SszMerkleizer.Chunkify(data);
// Result: 2 chunks
// Chunk 0: bytes 0-31 (full)
// Chunk 1: bytes 32-39 + 24 zero bytes (padded)
Assert.Equal(2, chunks.Count);
Assert.Equal(32, chunks[0].Length);
Assert.Equal(32, chunks[1].Length);
// First chunk contains first 32 bytes
Assert.Equal(data.Take(32), chunks[0]);
// Second chunk contains remaining 8 bytes + padding
Assert.Equal(data.Skip(32), chunks[1].Take(8));
Assert.All(chunks[1].Skip(8), b => Assert.Equal(0, b));
Source: tests/Nethereum.Ssz.Tests/SszMerkleizerTests.cs
using Nethereum.Ssz;
using System.Collections.Generic;
// Create chunks for a vector
var chunkA = new byte[32];
var chunkB = new byte[32];
chunkB[0] = 0x01;
var chunks = new List<byte[]> { chunkA, chunkB };
// Compute hash tree root with length mixed in
byte[] root = SszMerkleizer.HashTreeRootVector(chunks, length: 2);
// Different length = different root (even with same data)
byte[] differentRoot = SszMerkleizer.HashTreeRootVector(chunks, length: 1);
Assert.NotEqual(root, differentRoot);
// Hash tree root = MixInLength(Merkleize(chunks), length)
// Final hash includes both the data and its length
Source: tests/Nethereum.Ssz.Tests/SszMerkleizerTests.cs
using Nethereum.Ssz;
// Register a custom reader for a type
public class MyCustomType
{
public ulong Value1 { get; set; }
public ushort Value2 { get; set; }
}
public class MyCustomTypeReader : ISszElementReader<MyCustomType>
{
public MyCustomType Read(ref SszReader reader)
{
return new MyCustomType
{
Value1 = reader.ReadUInt64(),
Value2 = reader.ReadUInt16()
};
}
}
// Register the reader
SszElementReaderRegistry.Register(new MyCustomTypeReader());
// Now you can use it with ReadList
byte[] buffer = /* SSZ-encoded list */;
var reader = new SszReader(buffer);
MyCustomType[] items = SszReader.ReadList<MyCustomType>(ref reader, count: 5);
Source: src/Nethereum.Ssz/SszElementReaderRegistry.cs
using Nethereum.Ssz;
using var writer = new SszWriter();
// Fixed bytes: MUST be exact length
var fixedData = new byte[32];
writer.WriteFixedBytes(fixedData, expectedLength: 32); // OK
// This throws ArgumentException (length mismatch)
var wrongSize = new byte[4];
// writer.WriteFixedBytes(wrongSize, expectedLength: 32); // THROWS!
// Variable bytes: includes length prefix
var variableData = new byte[] { 0x01, 0x02, 0x03 };
writer.WriteVariableBytes(variableData); // Writes: [0x03,0x00,0x00,0x00,0x01,0x02,0x03]
// Can enforce max length
var tooLong = new byte[100];
// writer.WriteVariableBytes(tooLong, maxLength: 50); // THROWS!
byte[] encoded = writer.ToArray();
Source: tests/Nethereum.Ssz.Tests/SszWriterReaderTests.cs
Serializes data to SSZ format.
Constructor:
SszWriter() // Creates writer with internal MemoryStream
Primitive Methods:
void WriteBoolean(bool value): Write boolean (1 byte)void WriteUInt16(ushort value): Write 16-bit unsigned integer (little-endian)void WriteUInt32(uint value): Write 32-bit unsigned integer (little-endian)void WriteUInt64(ulong value): Write 64-bit unsigned integer (little-endian)Byte Array Methods:
void WriteFixedBytes(ReadOnlySpan<byte> bytes, int expectedLength): Write fixed-size byte array (validates length)void WriteVariableBytes(ReadOnlySpan<byte> bytes, ulong? maxLength = null): Write variable-size byte array (with length prefix)void WriteBytes(ReadOnlySpan<byte> bytes): Write raw bytes (no length prefix)Collection Methods:
void WriteList<T>(IList<T> items, Action<SszWriter, T> writeElement, ulong? maxLength = null): Write list with custom element writervoid WriteVector(IList<byte[]> items, int elementSize, int? expectedElementCount = null): Write fixed-size vectorOutput:
byte[] ToArray(): Get serialized bytesvoid Dispose(): Dispose underlying streamDeserializes SSZ-encoded data.
Constructor:
SszReader(ReadOnlySpan<byte> data) // Creates reader over byte span (ref struct)
Primitive Methods:
bool ReadBoolean(): Read boolean valueushort ReadUInt16(): Read 16-bit unsigned integer (little-endian)uint ReadUInt32(): Read 32-bit unsigned integer (little-endian)ulong ReadUInt64(): Read 64-bit unsigned integer (little-endian)Byte Array Methods:
byte[] ReadFixedBytes(int length): Read fixed-size byte arraybyte[] ReadVariableBytes(ulong? maxLength = null): Read variable-size byte array (reads length prefix first)Collection Methods:
static T[] ReadList<T>(ref SszReader reader, int count): Read list using registered element readerstatic T[] ReadList<T>(ref SszReader reader, int count, ISszElementReader<T> elementReader): Read list with custom element readerbyte[][] ReadVector(int elementCount, int elementSize): Read fixed-size vectorUtility:
byte[] ReadRemaining(): Read all remaining bytesComputes SHA-256 Merkle roots for SSZ types.
Static Methods:
byte[] Merkleize(IList<byte[]> chunks)
IList<byte[]> Chunkify(ReadOnlySpan<byte> data)
byte[] HashTreeRootVector(IList<byte[]> chunks, ulong length)
MixInLength(Merkleize(chunks), length)byte[] HashTreeRootList(IList<byte[]> chunks, ulong length)
byte[] MixInLength(byte[] root, ulong length)
SHA256(root || length_as_32_bytes)byte[] Merkleize(IList<byte[]> chunks, int limit)
next_power_of_two(limit) regardless of actual chunk countchunks.Count > limitbyte[] MerkleizeProgressive(IList<byte[]> chunks)
HashTreeRootProgressiveContainerbyte[] PackActiveFields(bool[] activeFields)
byte[] MixInActiveFields(byte[] root, bool[] activeFields)
SHA256(root || PackActiveFields(activeFields))byte[] HashTreeRootProgressiveContainer(IList<byte[]> fieldRoots, bool[] activeFields)
Nethereum.Model.SSZ for EIP-6404/6466/7807 typesbyte[] HashTreeRootProgressiveList(IList<byte[]> elementRoots)
byte[] HashTreeRootBasicProgressiveList(IList<byte[]> packedChunks, ulong elementCount)
byte[] HashTreeRootProgressiveBitlist(bool[] bits)
IList<byte[]> PackBitsToChunks(bool[] bits)
byte[] MixInSelector(byte[] root, byte selector)
SHA256(root || selector_as_32_bytes)byte[] HashTreeRootCompatibleUnion(byte[] dataRoot, byte selector)
MixInSelector — the canonical way to compute union rootsNethereum.Model.SSZ for transaction and receipt wrappersbool VerifyProof(byte[] leaf, IList<byte[]> branch, int depth, int index, byte[] root)
leaf: 32-byte leaf node to verifybranch: list of sibling hashes along the path (must contain at least depth entries)depth: number of levels in the proofindex: position of the leaf in the tree (bit flags determine left/right at each level)root: expected 32-byte Merkle roottrue if the proof is valid, false otherwiseRegistry for type-specific SSZ readers.
ISszElementReader<T>
public interface ISszElementReader<T>
{
T Read(ref SszReader reader);
}
SszElementReaderRegistry
Static Methods:
static void Register<T>(ISszElementReader<T> reader): Register reader for type Tstatic ISszElementReader<T> Get<T>(): Get registered reader (throws if not found)Built-in Readers:
UInt64Reader: Registered by default for ulongSSZ uses little-endian for all multi-byte integers:
// uint32 value = 0x12345678
// SSZ encoding: [0x78, 0x56, 0x34, 0x12]
// RLP encoding: [0x12, 0x34, 0x56, 0x78] (different!)
Always use SSZ for consensus layer, RLP for execution layer.
SSZ Merkleization uses SHA-256:
Never mix the two!
Fixed-Size (known at compile time):
bool, uint16, uint32, uint64Bytes[32]Vector[T, N]Variable-Size (length encoded):
BytesList[T, N]Variable-size types require a 4-byte length prefix (little-endian uint32).
SSZ uses 32-byte chunks for Merkleization:
Always specify maxLength for variable-size types:
writer.WriteVariableBytes(data, maxLength: 2048);
reader.ReadVariableBytes(maxLength: 2048);
Prevents denial-of-service attacks with oversized data.
SszReader is a ref struct:
SszWriter uses MemoryStream:
ToArray() allocates a copyMerkleization:
SszWriterReadList<T>| Feature | SSZ | RLP |
|---|---|---|
| Endianness | Little-endian | Big-endian |
| Type System | Strongly typed | Weakly typed |
| Hash Function | SHA-256 | Keccak-256 |
| Use Case | Consensus layer | Execution layer |
| Merkleization | Built-in | Separate (Patricia trie) |
| Variable Length | 4-byte prefix | Prefix length varies |
Length Limits:
Chunk Padding:
Type Safety:
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 net6.0 is compatible. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 1 NuGet packages that depend on Nethereum.Ssz:
| Package | Downloads |
|---|---|
|
Nethereum.Consensus.Ssz
Light client SSZ container implementations for beacon/consensus types. |
This package is not used by any popular GitHub repositories.