Esempio n. 1
0
def test_unsign_integers_more_than_32_bytes(data, num_bits):
    uint_n = UInt(num_bits)
    value = data.draw(st.integers(
        min_value=0,
        max_value=2**num_bits - 1,
    ))
    expected = hash_eth2(value.to_bytes(num_bits // 8, "little"))
    assert hash_tree_root(value, uint_n) == expected
Esempio n. 2
0
def hash_layer(child_layer: Sequence[bytes]) -> Tuple[Hash32, ...]:
    if len(child_layer) % 2 != 0:
        raise ValueError("Layer must have an even number of elements")

    child_pairs = partition(2, child_layer)
    parent_layer = tuple(
        hash_eth2(left_child + right_child)
        for left_child, right_child in child_pairs)
    return parent_layer
Esempio n. 3
0
    def merge(leaf: bytes, leaf_index: int) -> None:
        node = leaf
        layer = 0
        while True:
            if leaf_index & (1 << layer) == 0:
                if leaf_index == chunk_len and layer < chunk_depth:
                    # Keep going if we are complementing the void to the next power of 2
                    key = node + ZERO_HASHES[layer]
                    if key not in cache:
                        cache[key] = hash_eth2(key)
                    node = cache[key]
                else:
                    break
            else:
                key = merkleized_result_per_layers[layer] + node
                if key not in cache:
                    cache[key] = hash_eth2(key)
                node = cache[key]
            layer += 1

        merkleized_result_per_layers[layer] = node
Esempio n. 4
0
def hash_layer(child_layer: RawHashTreeLayer,
               layer_index: int) -> RawHashTreeLayer:
    if len(child_layer) % 2 == 0:
        padded_child_layer = child_layer
    else:
        padded_child_layer = child_layer.append(ZERO_HASHES[layer_index])

    child_pairs = partition(2, padded_child_layer)
    parent_layer = pvector(
        hash_eth2(left_child + right_child)
        for left_child, right_child in child_pairs)
    return parent_layer
Esempio n. 5
0
def _get_merkleized_result(
    chunks: Sequence[Hash32],
    chunk_len: int,
    chunk_depth: int,
    max_depth: int,
    cache: CacheObj,
) -> Tuple[Hash32, CacheObj]:
    merkleized_result_per_layers = [None for _ in range(max_depth + 1)]

    def merge(leaf: bytes, leaf_index: int) -> None:
        node = leaf
        layer = 0
        while True:
            if leaf_index & (1 << layer) == 0:
                if leaf_index == chunk_len and layer < chunk_depth:
                    # Keep going if we are complementing the void to the next power of 2
                    key = node + ZERO_HASHES[layer]
                    if key not in cache:
                        cache[key] = hash_eth2(key)
                    node = cache[key]
                else:
                    break
            else:
                key = merkleized_result_per_layers[layer] + node
                if key not in cache:
                    cache[key] = hash_eth2(key)
                node = cache[key]
            layer += 1

        merkleized_result_per_layers[layer] = node

    # Merge in leaf by leaf.
    for leaf_index in range(chunk_len):
        merge(chunks[leaf_index], leaf_index)

    # Complement with 0 if empty, or if not the right power of 2
    if 1 << chunk_depth != chunk_len:
        merge(ZERO_HASHES[0], chunk_len)

    # The next power of two may be smaller than the ultimate virtual size,
    # complement with zero-hashes at each depth.
    for layer in range(chunk_depth, max_depth):
        key = merkleized_result_per_layers[layer] + ZERO_HASHES[layer]
        if key not in cache:
            cache[key] = hash_eth2(
                merkleized_result_per_layers[layer] + ZERO_HASHES[layer]
            )
        merkleized_result_per_layers[layer + 1] = cache[key]

    root = merkleized_result_per_layers[max_depth]

    return root, cache
Esempio n. 6
0
def merklize_elements(elements: Sequence[ProofElement]) -> Hash32:
    """
    Given a set of `ProofElement` compute the `hash_tree_root`.

    This also verifies that the proof is both "well-formed" and "minimal".
    """
    elements_by_depth = groupby(operator.attrgetter("depth"), elements)
    max_depth = max(elements_by_depth.keys())

    for depth in range(max_depth, 0, -1):
        try:
            elements_at_depth = sorted(elements_by_depth.pop(depth))
        except KeyError:
            continue

        # Verify that all of the paths at this level are unique
        paths = set(el.path for el in elements_at_depth)
        if len(paths) != len(elements_at_depth):
            raise BrokenTree(
                f"Duplicate paths detected: depth={depth}  elements={elements_at_depth}"
            )

        sibling_pairs = tuple(
            (left, right)
            for left, right in sliding_window(2, elements_at_depth)
            if left.path[:-1] == right.path[:-1])

        # Check to see if any of the elements didn't have a sibling which
        # indicates either a missing sibling, or a duplicate node.
        orphans = set(elements_at_depth).difference(
            itertools.chain(*sibling_pairs))
        if orphans:
            raise BrokenTree(
                f"Orphaned tree elements: dept={depth} orphans={orphans}")

        parents = tuple(
            ProofElement(path=left.path[:-1],
                         value=hash_eth2(left.value + right.value))
            for left, right in sibling_pairs)

        if not elements_by_depth and len(parents) == 1:
            return parents[0].value
        else:
            elements_by_depth.setdefault(depth - 1, [])
            elements_by_depth[depth - 1].extend(parents)
    else:
        raise BrokenTree("Unable to fully collapse tree within 32 rounds")
Esempio n. 7
0
def generate_chunk_tree_padding(
        unpadded_chunk_tree: PVector[Hash32],
        chunk_count: Optional[int]) -> Generator[Hash32, None, None]:
    if chunk_count is None:
        return

    num_chunks = len(unpadded_chunk_tree[0])
    if num_chunks > chunk_count:
        raise ValueError(
            f"Number of chunks in tree ({num_chunks}) exceeds chunk count {chunk_count}"
        )

    num_existing_layers = len(unpadded_chunk_tree)
    num_target_layers = get_next_power_of_two(chunk_count).bit_length()

    previous_root = unpadded_chunk_tree[-1][0]
    for previous_layer_index in range(num_existing_layers - 1,
                                      num_target_layers - 1):
        next_root = hash_eth2(previous_root +
                              ZERO_HASHES[previous_layer_index])
        yield pvector([next_root])
        previous_root = next_root
Esempio n. 8
0
def recompute_hash_in_tree(hash_tree: RawHashTree, layer_index: int,
                           hash_index: int) -> RawHashTree:
    if layer_index == 0:
        raise ValueError(
            "Cannot recompute hash in leaf layer as it consists of chunks not hashes"
        )

    child_layer_index = layer_index - 1
    left_child_hash_index = hash_index * 2
    right_child_hash_index = left_child_hash_index + 1

    child_layer = hash_tree[child_layer_index]
    left_child_hash = child_layer[left_child_hash_index]
    try:
        right_child_hash = child_layer[right_child_hash_index]
    except IndexError:
        right_child_hash = ZERO_HASHES[child_layer_index]

    # create the layer if it doesn't exist yet (otherwise, pyrsistent would create a PMap)
    if layer_index == len(hash_tree):
        hash_tree = hash_tree.append(pvector())

    parent_hash = hash_eth2(left_child_hash + right_child_hash)
    return hash_tree.transform((layer_index, hash_index), parent_hash)
Esempio n. 9
0
def test_merkle_hash(value, expected):
    assert merkle_hash(value) == hash_eth2(expected)
Esempio n. 10
0
_type_2 = SSZType2(_type_1_a.copy(), [_type_1_a.copy(), _type_1_b.copy()])
_type_3 = SSZType3(1, 2, 3)
_type_undeclared_fields = SSZUndeclaredFieldsType()


@pytest.mark.parametrize(
    'value,sedes',
    (
        (_type_1_a, SSZType1),
        (_type_1_b, SSZType1),
        (_type_2, SSZType2),
    ),
)
def test_serializables(value, sedes):

    assert len(hash_tree_root(value, sedes)) == 32
    # Also make sure `infer_sedes` works
    assert len(hash_tree_root(value)) == 32


@pytest.mark.parametrize(
    'value,sedes,expected',
    (
        (_type_3, SSZType3, hash_tree_root(_type_3, SSZType4)),
        (_type_undeclared_fields, SSZUndeclaredFieldsType, hash_eth2(b'')),
    ),
)
def test_special_serializables(value, sedes, expected):
    assert hash_tree_root(value, sedes) == expected
    assert hash_tree_root(value) == expected
Esempio n. 11
0
 def intermediate_tree_hash(self, value: TSerializable) -> bytes:
     serialized = self.serialize(value)
     if self.length <= 32:
         return serialized
     else:
         return hash_eth2(serialized)
Esempio n. 12
0
from eth_typing import Hash32
from eth_utils.toolz import iterate, take

from ssz.hash import hash_eth2

CHUNK_SIZE = 32  # named BYTES_PER_CHUNK in the spec
EMPTY_CHUNK = Hash32(b"\x00" * CHUNK_SIZE)

SIGNATURE_FIELD_NAME = "signature"

# number of bytes for a serialized offset
OFFSET_SIZE = 4

FIELDS_META_ATTR = "fields"

ZERO_BYTES32 = Hash32(b"\x00" * 32)
MAX_ZERO_HASHES_LAYER = 100
ZERO_HASHES = tuple(
    take(
        MAX_ZERO_HASHES_LAYER,
        iterate(lambda child: hash_eth2(child + child), ZERO_BYTES32),
    ))

BASE_TYPES = (int, bytes, bool)
Esempio n. 13
0
 def intermediate_tree_hash(self, value: BytesOrByteArray) -> bytes:
     return hash_eth2(self.serialize(value))
Esempio n. 14
0

@given(st.binary())
def test_pack_bytes(data):
    byte_list = tuple(bytes([byte]) for byte in data)
    assert pack_bytes(data) == pack(byte_list)


@pytest.mark.parametrize(("chunks", "root"), (
    (
        (A_CHUNK,),
        A_CHUNK,
    ),
    (
        (A_CHUNK, B_CHUNK),
        hash_eth2(A_CHUNK + B_CHUNK),
    ),
    (
        (A_CHUNK, B_CHUNK, C_CHUNK),
        hash_eth2(hash_eth2(A_CHUNK + B_CHUNK) + hash_eth2(C_CHUNK + EMPTY_CHUNK)),
    ),
    (
        (A_CHUNK, B_CHUNK, C_CHUNK, D_CHUNK),
        hash_eth2(hash_eth2(A_CHUNK + B_CHUNK) + hash_eth2(C_CHUNK + D_CHUNK)),
    ),
))
def test_merkleize(chunks, root):
    assert merkleize(chunks) == root


@pytest.mark.parametrize(("root", "length", "result"), (
Esempio n. 15
0
        (
            (
                b'\x01',
                b'\x01',
                b'\x01',
            ),
            b'\x01\x01\x01' + b'\x00' * 125 + int(3).to_bytes(32, "little"),
        ),
        # two items in one chunk
        (
            (
                b'\x55' * 64,
                b'\x66' * 64,
                b'\x77' * 64,
            ),
            (hash_eth2(b'\x55' * 64 + b'\x66' * 64 + b'\x77' * 64 +
                       b'\x00' * 64) + int(3).to_bytes(32, "little")),
        ),
        (
            (b'\x55' * 96, b'\x66' * 96, b'\x77' * 96, b'\x88' * 96),
            (hash_eth2(
                (hash_eth2(b'\x55' * 96 + b'\x00' * 32 + b'\x66' * 96 +
                           b'\x00' * 32) +
                 hash_eth2(b'\x77' * 96 + b'\x00' * 32 + b'\x88' * 96 +
                           b'\x00' * 32))) + int(4).to_bytes(32, "little")),
        ),
    ),
)
def test_merkle_hash(value, expected):
    assert merkle_hash(value) == hash_eth2(expected)
Esempio n. 16
0
 def intermediate_tree_hash(self, value: TAnyTypedDict) -> bytes:
     field_hashes = [
         field_sedes.intermediate_tree_hash(value[field_name])
         for field_name, field_sedes in self.fields
     ]
     return hash_eth2(b"".join(field_hashes))
Esempio n. 17
0
def test_proof_get_minimal_proof_elements_mixed_depths():
    r"""
    0:                                X
                                     / \
                                   /     \
    1:                            0       1
                                 / \   (length)
                               /     \
                             /         \
                           /             \
                         /                 \
                       /                     \
                     /                         \
    2:              0                           1
                  /   \                       /   \
                /       \                   /       \
              /           \               /           \
    3:       0             1             0             1
            / \           / \           / \           / \
           /   \         /   \         /   \         /   \
    4:    0     1       0     1       X     X       0     1
         / \   / \     / \   / \     / \   / \     / \   / \
    5:  0   1 X   X   0   1 0   1   X   X X   X   0   1 X   X

    Nodes marked with `X` have already been collapsed

    Tests:
    A: |<--------->|
    B:                             |<----------------------->|
    """
    full_proof = compute_proof(CONTENT_512, sedes=short_content_sedes)

    section_a = full_proof.get_elements_under(p(0, 0, 0, 0))
    section_b = full_proof.get_minimal_proof_elements(2, 2)
    section_c = full_proof.get_elements_under(p(0, 0, 1))
    section_d = full_proof.get_minimal_proof_elements(8, 4)
    section_e = full_proof.get_elements_under(p(0, 1, 1, 0))
    section_f = full_proof.get_minimal_proof_elements(14, 2)
    section_g = (full_proof.get_element((True, )), )

    sparse_elements = sum(
        (
            section_a,
            section_b,
            section_c,
            section_d,
            section_e,
            section_f,
            section_g,
        ),
        (),
    )
    sparse_proof = Proof(
        elements=sparse_elements,
        sedes=short_content_sedes,
    )
    validate_proof(sparse_proof)

    # spans nodes at different levels
    elements_a = sparse_proof.get_minimal_proof_elements(0, 4)
    assert len(elements_a) == 1
    assert elements_a[0].path == p(0, 0, 0)
    assert elements_a[0].value == hash_eth2(
        hash_eth2(CONTENT_512[0:64]) + hash_eth2(CONTENT_512[64:128]))

    elements_b = sparse_proof.get_minimal_proof_elements(8, 8)
    assert len(elements_b) == 1
    assert elements_b[0].path == p(0, 1)
    hash_010 = hash_eth2(
        hash_eth2(CONTENT_512[256:320]) + hash_eth2(CONTENT_512[320:384]))
    hash_011 = hash_eth2(
        hash_eth2(CONTENT_512[384:448]) + hash_eth2(CONTENT_512[448:512]))
    assert elements_b[0].value == hash_eth2(hash_010 + hash_011)
Esempio n. 18
0
def test_proof_get_minimal_proof_elements_all_leaves():
    r"""
    0:                                X
                                     / \
                                   /     \
    1:                            0       1
                                 / \   (length)
                               /     \
                             /         \
                           /             \
                         /                 \
                       /                     \
                     /                         \
    2:              0                           1
                  /   \                       /   \
                /       \                   /       \
              /           \               /           \
    3:       0             1             0             1
            / \           / \           / \           / \
           /   \         /   \         /   \         /   \
    4:    0     1       0     1       0     1       0     1
         / \   / \     / \   / \     / \   / \     / \   / \
    5:  0   1 0   1   0   1 0   1   0   1 0   1   0   1 0   1

    Tests:
    A: |-|
    B:     |-|
    C:                         |-|
    D: |<--->|
    E:               |<--->|
    F:     |<->|
    G: |<----->|
    H:     |<----->|
    I:     |<----------------------->|
    """
    proof = compute_proof(CONTENT_512, sedes=short_content_sedes)

    # Just a single node
    elements_a = proof.get_minimal_proof_elements(0, 1)
    assert len(elements_a) == 1
    assert elements_a[0].path == p(0, 0, 0, 0, 0)
    assert elements_a[0].value == CONTENT_512[:32]

    elements_b = proof.get_minimal_proof_elements(1, 1)
    assert len(elements_b) == 1
    assert elements_b[0].path == p(0, 0, 0, 0, 1)
    assert elements_b[0].value == CONTENT_512[32:64]

    elements_c = proof.get_minimal_proof_elements(7, 1)
    assert len(elements_c) == 1
    assert elements_c[0].path == p(0, 0, 1, 1, 1)
    assert elements_c[0].value == CONTENT_512[224:256]

    # pair of sibling nodes
    elements_d = proof.get_minimal_proof_elements(0, 2)
    assert len(elements_d) == 1
    assert elements_d[0].path == p(0, 0, 0, 0)
    assert elements_d[0].value == hash_eth2(CONTENT_512[0:64])

    elements_e = proof.get_minimal_proof_elements(4, 2)
    assert len(elements_e) == 1
    assert elements_e[0].path == p(0, 0, 1, 0)
    assert elements_e[0].value == hash_eth2(CONTENT_512[128:192])

    # pair of non-sibling nodes
    elements_f = proof.get_minimal_proof_elements(1, 2)
    assert len(elements_f) == 2
    assert elements_f[0].path == p(0, 0, 0, 0, 1)
    assert elements_f[0].value == CONTENT_512[32:64]
    assert elements_f[1].path == p(0, 0, 0, 1, 0)
    assert elements_f[1].value == CONTENT_512[64:96]

    # disjoint sets of three
    elements_g = proof.get_minimal_proof_elements(0, 3)
    assert len(elements_g) == 2
    assert elements_g[0].path == p(0, 0, 0, 0)
    assert elements_g[0].value == hash_eth2(CONTENT_512[0:64])
    assert elements_g[1].path == p(0, 0, 0, 1, 0)
    assert elements_g[1].value == CONTENT_512[64:96]

    elements_h = proof.get_minimal_proof_elements(1, 3)
    assert len(elements_h) == 2
    assert elements_h[0].path == p(0, 0, 0, 0, 1)
    assert elements_h[0].value == CONTENT_512[32:64]
    assert elements_h[1].path == p(0, 0, 0, 1)
    assert elements_h[1].value == hash_eth2(CONTENT_512[64:128])

    # span of 8
    elements_i = proof.get_minimal_proof_elements(1, 8)
    assert len(elements_i) == 4
    assert elements_i[0].path == p(0, 0, 0, 0, 1)
    assert elements_i[0].value == CONTENT_512[32:64]
    assert elements_i[1].path == p(0, 0, 0, 1)
    assert elements_i[1].value == hash_eth2(CONTENT_512[64:128])
    assert elements_i[2].path == p(0, 0, 1)
    assert elements_i[2].value == hash_eth2(
        hash_eth2(CONTENT_512[128:192]) + hash_eth2(CONTENT_512[192:256]))
    assert elements_i[3].path == p(0, 1, 0, 0, 0)
    assert elements_i[3].value == CONTENT_512[256:288]
Esempio n. 19
0
def mix_in_length(root: Hash32, length: int) -> Hash32:
    return hash_eth2(root + length.to_bytes(CHUNK_SIZE, "little"))
Esempio n. 20
0
bytes16 = ByteVector(16)
EMPTY_BYTES = b"\x00" * 16
A_BYTES = b"\xaa" * 16
B_BYTES = b"\xbb" * 16
C_BYTES = b"\xcc" * 16
D_BYTES = b"\xdd" * 16
E_BYTES = b"\xee" * 16


@pytest.mark.parametrize(("serialized_uints128", "result"), (
    ((), EMPTY_CHUNK),
    ((A_BYTES, ), A_BYTES + EMPTY_BYTES),
    ((A_BYTES, B_BYTES), A_BYTES + B_BYTES),
    (
        (A_BYTES, B_BYTES, C_BYTES),
        hash_eth2(A_BYTES + B_BYTES + C_BYTES + EMPTY_BYTES),
    ),
    (
        (A_BYTES, B_BYTES, C_BYTES, D_BYTES, E_BYTES),
        hash_eth2(
            hash_eth2(A_BYTES + B_BYTES + C_BYTES + D_BYTES) +
            hash_eth2(E_BYTES + 3 * EMPTY_BYTES)),
    ),
))
def test_vector_of_basics(serialized_uints128, result):
    sedes = Vector(uint128, len(serialized_uints128))
    int_values = tuple(
        ssz.decode(value, uint128) for value in serialized_uints128)
    assert ssz.hash_tree_root(int_values, sedes) == result