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))
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
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())
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)
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, )
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)
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))
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)
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)
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())
def default_node(cls) -> Node: return subtree_fill_to_contents( [field.default_node() for field in cls.fields().values()], cls.tree_depth())