Simple Serialize (SSZ)

This section contains information and functions related to Simple Serialize (SSZ) in Prysm.

Simple Serialize (also known as SSZ) is the serialization algorithm standard for all data structures common across Ethereum 2.0 client implementations. It is outlined in the official Ethereum 2.0 specification.

Simple Serialize contains support for bool, uint8, uint16, uint32, uint64, slice, array, struct and pointer data types.

SSZ functionality

Marshal / Unmarshal

Our simple serialize API is designed to match the syntax of the popular JSON marshal / unmarshal API from the Go standard library. Below are samples of each in use.

marshal example:

// Marshal val and output the result.
func Marshal(val interface{}) ([]byte, error)

unmarshal example:

// Unmarshal data from input and output it into the object pointed by pointer val.
func Unmarshal(input []byte, val interface{}) error

Tree hashing

HashTreeRoot SSZ marshals a value and packs its serialized bytes into leaves of a Merkle trie. It then determines the root of this trie.

HashTreeRootexample:

func HashTreeRoot(val interface{}) ([32]byte, error)

Usage examples

Encoding an object (Marshal)

  1. To begin, we create this basic struct:

type exampleStruct1 struct {
Field1 uint8
Field2 []byte
}
  1. Next, we can encode the defined object like so:

e1 := exampleStruct1{
Field1: 10,
Field2: []byte{1, 2, 3, 4},
}
encoded, err := Marshal(e1)
if err != nil {
return fmt.Errorf("failed to marshal: %v", err)
}
  1. (Optional) It is also possible to specify the size of a struct's field by utilising ssz-specific field tags:

type exampleStruct struct {
Field1 uint8
Field2 []byte `ssz:"size=32"`
}

This will treat Field2 as as [32]byte array when marshaling.

  1. (Optional) For unbounded fields or multidimensional slices, SSZ size tags can also be used:

type exampleStruct struct {
Field1 uint8
Field2 [][]byte `ssz:"size=?,32"`
}

This will treat Field2 as type [][32]byte when marshaling a struct of that type.

Decoding an object (Unmarshal)

  1. Similarly, you can unmarshal encoded bytes into its original form:

var e2 exampleStruct
if err = Unmarshal(encoded, &e2); err != nil {
return fmt.Errorf("failed to unmarshal: %v", err)
}
reflect.DeepEqual(e1, e2) // Returns true as e2 now has the same content as e1.

Calculating the tree-hash (HashTreeRoot)

  1. To calculate tree-hash root of the object run:

root, err := HashTreeRoot(e1)
if err != nil {
return fmt.Errorf("failed to compute Merkle root: %v", err)
}