Typing


Types


All SSZ Objects represent data of one of these Types:


  • Basic Types:
    • Unisigned Integer
      • Uint8, Uint16, Uint32, Uint64, Uint128, Uint256
    • Boolean
      • Bit, 0 or 1, True or False
  • Composite Types
    • Vector
      • "Fixed Length" sequence of elements of same **Type** (homogeneous)
    • List
      • "Variable Length" sequence of elements of the same **Type** (homogenous)
    • Container
      • Heterogeneous ordered collection of elements
    • Union
      • A "Union Type" containing SSZ Types
    • Root
      • A Uint256 that represents the Bytes32 hash_tree_root of a nested merkle tree


Aliases


Types can be aliased to more specific types, good use of type aliasing can make a data-structure much clearer.
E.g. BLSSignature instead of Vector[byte, 96].

Default values


All SSZ Types have a default "zeroed" value

  • Uint: 0
  • Boolean: False
  • Vector: Sequence of default values
  • List: Empty List
  • Container: Default value for each type in container
  • Union: Default value of "Type_0"

Default values are recursive; elements in composite types such as containers are initialized with their respective default initializations


Merkle proofs


Every type deterministically describes the shape of the Merkle Tree representing the type

Most types do so statically: the shape can be constructed on compile time, and navigation is stable (See generalized indices).


Mapping a valid (to the type) merkle tree to that same type is bijective:


  • No two different values of the same type can merkleize to the same root
  • No two roots can be derived for the same value of the type used for the root.

Different types may merkleize to the same root:


1. Intentionally: see summaries and expansions.

or

2. Because different types have the same structure
  • Two values of different types can merkleize to the same root
    • e.g. a uint256(123) and uint8(123) have the same root.
    • Or more exceptionally, a Container with 4 Bytes32 fields can have the same root as a Vector[uint64, 16].


Representation


Mapping valid instances of the same type to a byte sequence is bijective:


  • Serialization: Any two different values of the same type cannot have the same representation.

  • Deserialization: Any valid representation of a given type cannot be interpreted as two different values of that same type:


Mapping any instance of a type to any byte sequence is injective and non-surjective:


  • Serialization: All type instantiations can be serialized to a unique (to the type) value.

  • Deserialization: not all byte sequences are a valid representation for a given type, because of constraints such as: