Esempio n. 1
0
 def deserialize(cls: Type[V], stream: BinaryIO, scope: int) -> V:
     if scope < 1:
         raise Exception("cannot have empty scope for bitlist, need at least a delimiting bit")
     if scope > cls.max_byte_length():
         raise Exception(f"scope is too large: {scope}, max bitlist byte length is: {cls.max_byte_length()}")
     chunks: PyList[Node] = []
     bytelen = scope - 1  # excluding the last byte (which contains the delimiting bit)
     while scope > 32:
         chunks.append(RootNode(Root(stream.read(32))))
         scope -= 32
     # scope is [1, 32] here
     last_chunk_part = stream.read(scope)
     last_byte = int(last_chunk_part[scope-1])
     if last_byte == 0:
         raise Exception("last byte must not be 0: bitlist requires delimiting bit")
     last_byte_bitlen = last_byte.bit_length() - 1  # excluding the delimiting bit
     bitlen = bytelen * 8 + last_byte_bitlen
     if bitlen % 256 != 0:
         last_chunk = last_chunk_part[:scope-1] +\
                      (last_byte ^ (1 << last_byte_bitlen)).to_bytes(length=1, byteorder='little')
         last_chunk += b"\x00" * (32 - len(last_chunk))
         chunks.append(RootNode(Root(last_chunk)))
     if bitlen > cls.limit():
         raise Exception(f"bitlist too long: {bitlen}, delimiting bit is over limit ({cls.limit()})")
     contents = subtree_fill_to_contents(chunks, cls.contents_depth())
     backing = PairNode(contents, uint256(bitlen).get_backing())
     return cast(Bitlist, cls.view_from_backing(backing))
Esempio n. 2
0
    def __new__(cls,
                *args,
                backing: Optional[Node] = None,
                hook: Optional[ViewHook] = None,
                **kwargs):
        if backing is not None:
            if len(args) != 0:
                raise Exception(
                    "cannot have both a backing and elements to init List")
            return super().__new__(cls, backing=backing, hook=hook, **kwargs)

        input_nodes = []
        for fkey, ftyp in cls.fields().items():
            fnode: Node
            if fkey in kwargs:
                finput = kwargs.pop(fkey)
                if isinstance(finput, View):
                    fnode = finput.get_backing()
                else:
                    fnode = ftyp.coerce_view(finput).get_backing()
            else:
                fnode = ftyp.default_node()
            input_nodes.append(fnode)
        # check if any keys are remaining to catch unrecognized keys
        if len(kwargs) > 0:
            raise AttributeError(
                f'The field names [{"".join(kwargs.keys())}] are not defined in {cls}'
            )
        backing = subtree_fill_to_contents(input_nodes, cls.tree_depth())
        out = super().__new__(cls, backing=backing, hook=hook)
        return out
Esempio n. 3
0
 def get_backing(self) -> Node:
     if len(self) == 32:  # super common case, optimize for it
         return RootNode(Root(self))
     elif len(self) < 32:
         return RootNode(Root(self + b"\x00" * (32 - len(self))))
     else:
         return subtree_fill_to_contents(pack_bytes_to_chunks(self), self.__class__.tree_depth())
Esempio n. 4
0
 def __new__(cls, *args, **kwargs):
     vals = list(args)
     if len(vals) > 0:
         if len(vals) == 1 and isinstance(vals[0], (GeneratorType, list, tuple)):
             vals = list(vals[0])
         veclen = cls.vector_length()
         if len(vals) != veclen:
             raise Exception(f"incorrect bitvector input: {len(vals)} bits, vector length is: {veclen}")
         input_bits = list(map(bool, vals))
         input_nodes = pack_bits_to_chunks(input_bits)
         kwargs['backing'] = subtree_fill_to_contents(input_nodes, cls.tree_depth())
     return super().__new__(cls, **kwargs)
Esempio n. 5
0
def get_valid_custody_response(spec,
                               state,
                               bit_challenge,
                               custody_data,
                               challenge_index,
                               invalid_chunk_bit=False):
    chunks = custody_chunkify(spec, custody_data)

    chunk_index = len(chunks) - 1
    chunk_bit = spec.get_custody_chunk_bit(bit_challenge.responder_key,
                                           chunks[chunk_index])

    while chunk_bit == bit_challenge.chunk_bits[
            chunk_index] ^ invalid_chunk_bit:
        chunk_index -= 1
        chunk_bit = spec.get_custody_chunk_bit(bit_challenge.responder_key,
                                               chunks[chunk_index])

    chunks_hash_tree_roots = [
        hash_tree_root(ByteVector[spec.BYTES_PER_CUSTODY_CHUNK](chunk))
        for chunk in chunks
    ]
    chunks_hash_tree_roots += [
        hash_tree_root(ByteVector[spec.BYTES_PER_CUSTODY_CHUNK](
            b"\0" * spec.BYTES_PER_CUSTODY_CHUNK))
        for i in range(2**spec.ceillog2(len(chunks)) - len(chunks))
    ]
    data_tree = get_merkle_tree(chunks_hash_tree_roots)

    data_branch = get_merkle_proof(data_tree, chunk_index)

    bitlist_chunk_index = chunk_index // BYTES_PER_CHUNK
    print(bitlist_chunk_index)
    bitlist_chunk_nodes = pack_bits_to_chunks(bit_challenge.chunk_bits)
    bitlist_tree = subtree_fill_to_contents(bitlist_chunk_nodes,
                                            get_depth(spec.MAX_CUSTODY_CHUNKS))
    print(bitlist_tree)
    bitlist_chunk_branch = None  # TODO; extract proof from merkle tree

    bitlist_chunk_index = chunk_index // 256

    chunk_bits_leaf = Bitvector[256](
        bit_challenge.chunk_bits[bitlist_chunk_index *
                                 256:(bitlist_chunk_index + 1) * 256])

    return spec.CustodyResponse(
        challenge_index=challenge_index,
        chunk_index=chunk_index,
        chunk=ByteVector[spec.BYTES_PER_CUSTODY_CHUNK](chunks[chunk_index]),
        data_branch=data_branch,
        chunk_bits_branch=bitlist_chunk_branch,
        chunk_bits_leaf=chunk_bits_leaf,
    )
Esempio n. 6
0
 def __new__(cls, *args, **kwargs):
     vals = list(args)
     if len(vals) > 0:
         if len(vals) == 1 and isinstance(vals[0], (GeneratorType, list, tuple)):
             vals = list(vals[0])
         limit = cls.limit()
         if len(vals) > limit:
             raise Exception(f"too many bitlist inputs: {len(vals)}, limit is: {limit}")
         input_bits = list(map(bool, vals))
         input_nodes = pack_bits_to_chunks(input_bits)
         contents = subtree_fill_to_contents(input_nodes, cls.contents_depth())
         kwargs['backing'] = PairNode(contents, uint256(len(input_bits)).get_backing())
     return super().__new__(cls, **kwargs)
Esempio n. 7
0
 def deserialize(cls: Type[V], stream: BinaryIO, scope: int) -> V:
     if scope != cls.type_byte_length():
         raise Exception(f"scope is invalid: {scope}, bitvector byte length is: {cls.type_byte_length()}")
     chunks: PyList[Node] = []
     bytelen = scope - 1  # excluding the last byte
     while scope > 32:
         chunks.append(RootNode(Root(stream.read(32))))
         scope -= 32
     # scope is [1, 32] here
     last_chunk_part = stream.read(scope)
     last_byte = int(last_chunk_part[scope-1])
     bitlen = bytelen * 8 + last_byte.bit_length()
     if bitlen > cls.vector_length():
         raise Exception(f"bitvector too long: {bitlen}, last byte has bits over bit length ({cls.vector_length()})")
     last_chunk = last_chunk_part + (b"\x00" * (32 - len(last_chunk_part)))
     chunks.append(RootNode(Root(last_chunk)))
     backing = subtree_fill_to_contents(chunks, cls.tree_depth())
     return cast(Bitvector, cls.view_from_backing(backing))
Esempio n. 8
0
    def __new__(cls,
                *args,
                backing: Optional[Node] = None,
                hook: Optional[ViewHook] = None,
                **kwargs):
        if backing is not None:
            if len(args) != 0:
                raise Exception(
                    "cannot have both a backing and elements to init List")
            return super().__new__(cls, backing=backing, hook=hook, **kwargs)

        elem_cls = cls.element_cls()
        vals = list(args)
        if len(vals) == 1:
            val = vals[0]
            if isinstance(val, (GeneratorType, list, tuple)):
                vals = list(val)
            if issubclass(elem_cls, uint8):
                if isinstance(val, bytes):
                    vals = list(val)
                if isinstance(val, str):
                    if val[:2] == '0x':
                        val = val[2:]
                    vals = list(bytes.fromhex(val))
        if len(vals) > 0:
            limit = cls.limit()
            if len(vals) > limit:
                raise Exception(
                    f"too many list inputs: {len(vals)}, limit is: {limit}")
            input_views = []
            for el in vals:
                if isinstance(el, View):
                    input_views.append(el)
                else:
                    input_views.append(elem_cls.coerce_view(el))
            input_nodes = cls.views_into_chunks(input_views)
            contents = subtree_fill_to_contents(input_nodes,
                                                cls.contents_depth())
            backing = PairNode(contents,
                               uint256(len(input_views)).get_backing())
        return super().__new__(cls, backing=backing, hook=hook, **kwargs)
Esempio n. 9
0
    def __new__(cls,
                *args,
                backing: Optional[Node] = None,
                hook: Optional[ViewHook] = None,
                **kwargs):
        if backing is not None:
            if len(args) != 0:
                raise Exception(
                    "cannot have both a backing and elements to init Vector")
            return super().__new__(cls, backing=backing, hook=hook, **kwargs)

        elem_cls = cls.element_cls()
        vals = list(args)
        if len(vals) == 1:
            val = vals[0]
            if isinstance(val, (GeneratorType, list, tuple)):
                vals = list(val)
            if issubclass(elem_cls, uint8):
                if isinstance(val, bytes):
                    vals = list(val)
                if isinstance(val, str):
                    if val[:2] == '0x':
                        val = val[2:]
                    vals = list(bytes.fromhex(val))
        if len(vals) > 0:
            vector_length = cls.vector_length()
            if len(vals) != vector_length:
                raise Exception(
                    f"invalid inputs length: {len(vals)}, vector length is: {vector_length}"
                )
            input_views = []
            for el in vals:
                if isinstance(el, View):
                    input_views.append(el)
                else:
                    input_views.append(elem_cls.coerce_view(el))
            input_nodes = cls.views_into_chunks(input_views)
            backing = subtree_fill_to_contents(input_nodes, cls.tree_depth())
        return super().__new__(cls, backing=backing, hook=hook, **kwargs)
Esempio n. 10
0
 def get_backing(self) -> Node:
     return PairNode(
         subtree_fill_to_contents(pack_bytes_to_chunks(self),
                                  self.__class__.contents_depth()),
         uint256(len(self)).get_backing())
Esempio n. 11
0
 def default_node(cls) -> Node:
     return subtree_fill_to_contents(
         [field.default_node() for field in cls.fields().values()],
         cls.tree_depth())