def verify(self, uid, proof): """ Checks if the proof for the leaf at `uid` is valid""" # assert (len(proof) -8 % 32) == 0 assert len(proof) <= 2056 proofbits = int.from_bytes((proof[0:8]), byteorder='big') index = uid p = 8 if index in self.leaves: computed_hash = self.leaves[index] # in case the tx is not included, computed_hash is the default leaf else: computed_hash = self.default_nodes[-1] for d in range(self.depth): if proofbits % 2 == 0: proof_element = self.default_nodes[d] else: proof_element = proof[p:p + 32] p += 32 if index % 2 == 0: computed_hash = keccak(computed_hash + proof_element) else: computed_hash = keccak(proof_element + computed_hash) proofbits = proofbits // 2 index = index // 2 return computed_hash == self.root
def create_default_nodes(self, depth): # Default nodes are the nodes whose children are both empty nodes at # each level. default_hash = keccak(b'\x00' * 32) default_nodes = [default_hash] for level in range(1, depth + 1): prev_default = default_nodes[level - 1] default_nodes.append(keccak(prev_default * 2)) return default_nodes
def test_encode_basic_types(): class TestStruct(EIP712Struct): address = Address() boolean = Boolean() dyn_bytes = Bytes() bytes_1 = Bytes(1) bytes_32 = Bytes(32) int_32 = Int(32) int_256 = Int(256) string = String() uint_32 = Uint(32) uint_256 = Uint(256) values = dict() values['address'] = os.urandom(20) values['boolean'] = False values['dyn_bytes'] = os.urandom(random.choice(range(33, 100))) values['bytes_1'] = os.urandom(1) values['bytes_32'] = os.urandom(32) values['int_32'] = random.randint(*signed_min_max(32)) values['int_256'] = random.randint(*signed_min_max(256)) values['string'] = ''.join( [random.choice(string.ascii_letters) for _ in range(100)]) values['uint_32'] = random.randint(0, unsigned_max(32)) values['uint_256'] = random.randint(0, unsigned_max(256)) expected_data = list() expected_data.append(bytes(12) + values['address']) expected_data.append(bytes(32)) expected_data.append(keccak(values['dyn_bytes'])) expected_data.append(values['bytes_1'] + bytes(31)) expected_data.append(values['bytes_32']) expected_data.append(values['int_32'].to_bytes(32, byteorder='big', signed=True)) expected_data.append(values['int_256'].to_bytes(32, byteorder='big', signed=True)) expected_data.append(keccak(text=values['string'])) expected_data.append(values['uint_32'].to_bytes(32, byteorder='big', signed=False)) expected_data.append(values['uint_256'].to_bytes(32, byteorder='big', signed=False)) s = TestStruct(**values) encoded_data = s.encode_value() encoded_bytes = list() # Compare each byte range itself to find offenders for i in range(0, len(encoded_data), 32): encoded_bytes.append(encoded_data[i:i + 32]) assert encoded_bytes == expected_data
def test_encode_nested_structs(): class SubStruct(EIP712Struct): s = String() class MainStruct(EIP712Struct): sub_1 = SubStruct sub_2 = String() sub_3 = SubStruct s1 = 'foo' s2 = 'bar' s3 = 'baz' sub_1 = SubStruct(s=s1) sub_3 = SubStruct(s=s3) s = MainStruct( sub_1=sub_1, sub_2=s2, sub_3=sub_3, ) expected_encoded_vals = b''.join( [sub_1.hash_struct(), keccak(text=s2), sub_3.hash_struct()]) assert s.encode_value() == expected_encoded_vals
def test_sign(): print("sign test") # ac = Account.create("123456") # print("account priv key: ", ac.privateKey) privkey = "52413c714e418cc6fb06afb1bc3f6c54449c89a82a17c9a117a5aa0bad56a9cd" binprivkey = codecs.decode(privkey, "hex") pubkey = private_key_to_public_key(binprivkey) print("binary priv key: ", decode_hex(privkey)) print("binary pub key: ", pubkey) acforverify = Account.from_key(binprivkey) msg = b"this is a test" msghash = keccak(msg) sig = acforverify._key_obj.sign_msg_hash(msghash) print("pulic key :", acforverify.publickey) vresult = sig.verify_msg_hash(msghash, acforverify.publickey) print("verify result ", vresult) (v, r, s) = ecdsa_raw_sign(msghash, decode_hex(privkey)) vres = ecdsa_raw_verify(msghash, (r, s), pubkey) print("ecdsa raw verify: ", vres) recoverres = ecdsa_raw_recover(msghash, (v, r, s)) print("raw recover result", recoverres) print("hex recover result", encode_hex(recoverres))
def test_signable_bytes(): class Foo(EIP712Struct): s = String() i = Int(256) domain = make_domain(name='hello') foo = Foo(s='hello', i=1234) start_bytes = b'\x19\x01' exp_domain_bytes = keccak(domain.type_hash() + domain.encode_value()) exp_struct_bytes = keccak(foo.type_hash() + foo.encode_value()) sign_bytes = foo.signable_bytes(domain) assert sign_bytes[0:2] == start_bytes assert sign_bytes[2:34] == exp_domain_bytes assert sign_bytes[34:] == exp_struct_bytes
def hash_struct(tx, domain=None, verifyingContract=None): if domain and verifyingContract: raise RuntimeError("verifyingContract supplied but ignored") verifying_address = verifyingContract.address if verifyingContract else NULL_ADDRESS inputs = [ Input(blknum=i.blknum, txindex=i.txindex, oindex=i.oindex) for i in tx.inputs ] outputs = [ Output(owner=o.output_guard, currency=o.token, amount=o.amount) for o in tx.outputs ] domain = domain or make_domain( name='OMG Network', version='1', verifyingContract=verifying_address, salt=bytes.fromhex( 'fad5c7f626d80f9256ef01929f3beb96e058b8b4b0e3fe52d84f054c0e2a7a83') ) type = Transaction().encode_type() + Input.encode_type( ) + Output.encode_type() values = [_hash_typed(t) for t in inputs] + [_hash_typed(t) for t in outputs ] + [tx.metadata or NULL_HASH] return keccak(b'\x19\x01' + _hash_typed(domain) + _hash_struct(type, b''.join(values)))
def create_tree(self, ordered_leaves, depth, default_nodes): for leaf in ordered_leaves: ordered_leaves[leaf] = '0x' + keccak(ordered_leaves[leaf][0]).hex() tree = [ordered_leaves] tree_level = ordered_leaves for level in range(depth): next_level = {} for index, value in tree_level.items(): if index % 2 == 0: co_index = index + 1 if co_index in tree_level: next_level[index // 2] = self.hashPadded( value, tree_level[co_index]) else: next_level[index // 2] = self.hashPadded( value, default_nodes[level]) else: # If the node is a right node, check if its left sibling is # a default node. co_index = index - 1 if co_index not in tree_level: next_level[index // 2] = self.hashPadded( default_nodes[level], value) tree_level = next_level tree.append(tree_level) return tree
def test_create_merkle_proof(self): leaves = {0: dummy_val, 2: dummy_val, 3: dummy_val_2} tree = SparseMerkleTree(depth=2, leaves=leaves) mid_left_val = keccak(dummy_val + default_hash) mid_right_val = keccak(dummy_val + dummy_val_2) assert ( tree.create_merkle_proof(0) == (2).to_bytes(8, byteorder='big') + mid_right_val) assert ( tree.create_merkle_proof(1) == (3).to_bytes(8, byteorder='big') + dummy_val + mid_right_val) assert ( tree.create_merkle_proof(2) == (3).to_bytes(8, byteorder='big') + dummy_val_2 + mid_left_val) assert ( tree.create_merkle_proof(3) == (3).to_bytes(8, byteorder='big') + dummy_val + mid_left_val)
def test_encode_array(): class TestStruct(EIP712Struct): byte_array = Array(Bytes(32), 4) byte_array = [os.urandom(32) for _ in range(4)] s = TestStruct(byte_array=byte_array) assert s.encode_value() == keccak(b''.join(byte_array))
def to_eth(self) -> str: if self.version == Version.PRIVATE: return self.key.get_private_bytes().hex() else: if isinstance(self.key, Secp256k1Pub): return Web3.toChecksumAddress(keccak(self.key.key.public_bytes(Encoding.X962, PublicFormat.UncompressedPoint)[1:]).hex()[24:]) else: raise NotImplementedError("eth addr from non-public secp256k1")
def combine_hash(first: bytes, second: bytes) -> bytes: if not first: return second if not second: return first return keccak(primitive=b"".join(sorted([first, second])))
def generate_test_data(priv=None, msg=None): # return msg_hash, signature, pubkey if not priv: priv = os.urandom(32) pk = keys.PrivateKey(priv) if not msg: msg = os.urandom(randint(0, 1024)) signature = pk.sign_msg(msg) return keccak(msg).hex(), signature, pk.public_key.to_address()[2:]
def test_none_replacement(): class Foo(EIP712Struct): s = String() i = Int(256) foo = Foo(**{}) encoded_val = foo.encode_value() assert len(encoded_val) == 64 empty_string_hash = keccak(text='') assert encoded_val[0:32] == empty_string_hash assert encoded_val[32:] == bytes(32)
def sha3(primitive=None, text=None, hexstr=None): if isinstance(primitive, (bytes, int, type(None))): input_bytes = to_bytes(primitive, hexstr=hexstr, text=text) return keccak(input_bytes) raise TypeError( "You called sha3 with first arg %r and keywords %r. You must call it with one of " "these approaches: sha3(text='txt'), sha3(hexstr='0x747874'), " "sha3(b'\\x74\\x78\\x74'), or sha3(0x747874)." % (primitive, { 'text': text, 'hexstr': hexstr }))
def test_domain_sep_types(): salt = os.urandom(32) contract = os.urandom(20) domain_struct = make_domain(name='name', version='version', chainId=1, verifyingContract=contract, salt=salt) encoded_data = [ keccak(text='name'), keccak(text='version'), int(1).to_bytes(32, 'big', signed=False), bytes(12) + contract, salt ] expected_result = 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)' assert domain_struct.encode_type() == expected_result expected_data = b''.join(encoded_data) assert domain_struct.encode_value() == expected_data
def signed_tx(cls, sutx, v, r, s): enctx = encode_transaction(sutx, (v, r, s)) transaction_hash = keccak(enctx) attr_dict = AttributeDict({ 'rawTransaction': HexBytes(enctx), 'hash': HexBytes(transaction_hash), 'r': r, 's': s, 'v': v, }) return attr_dict
def test_domain_sep_create(): salt = os.urandom(32) domain_struct = make_domain(name='name', salt=salt) expected_result = 'EIP712Domain(string name,bytes32 salt)' assert domain_struct.encode_type() == expected_result expected_data = b''.join([keccak(text='name'), salt]) assert domain_struct.encode_value() == expected_data with pytest.raises(ValueError, match='At least one argument must be given'): make_domain()
def _encode_value(self, value): """Static bytesN types are encoded by right-padding to 32 bytes. Dynamic bytes types are keccak256 hashed.""" if isinstance(value, str): # Try converting to a bytestring, assuming that it's been given as hex value = to_bytes(hexstr=value) if self.length == 0: return keccak(value) else: if len(value) > self.length: raise ValueError( f'{self.type_name} was given bytes with length {len(value)}' ) padding = bytes(32 - len(value)) return value + padding
def create_tree(self, ordered_leaves, depth, default_nodes): tree = [ordered_leaves] tree_level = ordered_leaves for level in range(depth): next_level = {} for index, value in tree_level.items(): if index % 2 == 0: co_index = index + 1 if co_index in tree_level: next_level[index // 2] = keccak(value + tree_level[co_index]) else: next_level[index // 2] = keccak(value + default_nodes[level]) else: # If the node is a right node, check if its left sibling is # a default node. co_index = index - 1 if co_index not in tree_level: next_level[index // 2] = keccak(default_nodes[level] + value) tree_level = next_level tree.append(tree_level) return tree
def parse_sign_result(cls, tx, exchange_result): sign_v = exchange_result[0] sign_r = int((exchange_result[1:1 + 32]).hex(), 16) sign_s = int((exchange_result[1 + 32:1 + 32 + 32]).hex(), 16) enctx = encode_transaction(tx, (sign_v, sign_r, sign_s)) transaction_hash = keccak(enctx) signed_txn = AttributeDict({ 'rawTransaction': HexBytes(enctx), 'hash': HexBytes(transaction_hash), 'v': sign_v, 'r': sign_r, 's': sign_s, }) return signed_txn
def _encode_value(self, value): """Static bytesN types are encoded by right-padding to 32 bytes. Dynamic bytes types are keccak256 hashed.""" if isinstance(value, str): # Try converting to a bytestring, assuming that it's been given as hex if value.startswith('0x'): value = value[2:] else: raise ValueError( f'{self.type_name} was given an invalid hex string, not starting with "0x"' ) value = to_bytes(hexstr=HexStr(value)) if self.length == 0: return keccak(value) else: if len(value) != self.length: raise ValueError( f'{self.type_name} was given bytes with length {len(value)}' ) padding = bytes(32 - len(value)) return value + padding
def _hash_struct(type, value): return keccak(keccak(text=type) + value)
def _encode_value(self, value): """Arrays are encoded by concatenating their encoded contents, and taking the keccak256 hash.""" encoder = self.member_type encoded_values = [encoder.encode_value(v) for v in value] return keccak(b''.join(encoded_values))
def func_sign_to_4bytes(event_signature): """ASCII Keccak hash 4bytes """ return keccak(text=event_signature.replace(' ', ''))[:4]
def topic_from_string(value): s = encode_hex(keccak(bytes(value, "utf-8")))[2:] return "0x" + s
import pytest from eth_utils.crypto import keccak from hexbytes import HexBytes from utils.merkle.sparse_merkle_tree import SparseMerkleTree empty_val = b'\x00' * 32 default_hash = keccak(empty_val) dummy_val = keccak(2) dummy_val_2 = keccak(3) class TestSparseMerkleTree(object): def test_size_limits(self): with pytest.raises(SparseMerkleTree.TreeSizeExceededException): SparseMerkleTree(depth=0, leaves={0: '0', 1: '1'}) with pytest.raises(SparseMerkleTree.TreeSizeExceededException): SparseMerkleTree(depth=1, leaves={ 0: empty_val, 1: empty_val, 2: empty_val }) def test_empty_SMT(self): emptyTree = SparseMerkleTree(64, {}) assert len(emptyTree.leaves) == 0 def test_all_leaves_with_val(self): leaves = {0: dummy_val, 1: dummy_val, 2: dummy_val, 3: dummy_val} tree = SparseMerkleTree(depth=2, leaves=leaves)
def test_all_leaves_with_val(self): leaves = {0: dummy_val, 1: dummy_val, 2: dummy_val, 3: dummy_val} tree = SparseMerkleTree(depth=2, leaves=leaves) mid_level_val = keccak(dummy_val * 2) assert tree.root == keccak(mid_level_val + mid_level_val)
def test_empty_leaves(self): tree = SparseMerkleTree(depth=2) mid_level_val = keccak(default_hash * 2) assert tree.root == keccak(mid_level_val * 2)
def test_empty_right_leave(self): leaves = {0: dummy_val, 2: dummy_val, 3: dummy_val} tree = SparseMerkleTree(depth=2, leaves=leaves) mid_left_val = keccak(dummy_val + default_hash) mid_right_val = keccak(dummy_val * 2) assert tree.root == keccak(mid_left_val + mid_right_val)