Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 56 additions & 51 deletions crypto/identity/address.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,76 +4,81 @@
from crypto.identity.private_key import PrivateKey

from Cryptodome.Hash import keccak
from coincurve import PrivateKey, PublicKey
from coincurve import PublicKey

def get_checksum_address(address: str) -> str:
"""Get checksum address
class Address:
@classmethod
def from_public_key(cls, public_key: str) -> str:
"""Get an address from a public key

Args:
address (str): address to get checksum
Args:
public_key (str): public key to get address

Returns:
str: checksum address
"""
address = address.lower()
Returns:
str: address
"""

chars = list(address[2:])
public_key_bytes = PublicKey(bytes.fromhex(public_key)).format(compressed=False)[1:]

expanded = bytearray(40)
for i in range(40):
expanded[i] = ord(chars[i])
keccak_hash = keccak.new(
data=bytearray.fromhex(public_key_bytes.hex()),
digest_bits=256,
)

hashed = keccak.new(data=bytes(expanded), digest_bits=256).digest()
return cls.get_checksum_address(unhexlify(keccak_hash.hexdigest()[22:]).hex())

for i in range(0, 40, 2):
if (hashed[i >> 1] >> 4) >= 8:
chars[i] = chars[i].upper()
if (hashed[i >> 1] & 0x0F) >= 8:
chars[i + 1] = chars[i + 1].upper()
@classmethod
def from_private_key(cls, private_key: str) -> str:
"""Get an address from private key

return "0x" + ''.join(chars)
Args:
private_key (string): private key to get address

def address_from_public_key(public_key: str) -> str:
"""Get an address from a public key
Returns:
str: address
"""
private_key_object = PrivateKey.from_hex(private_key)

Args:
public_key (str): public key to get address
return cls.from_public_key(private_key_object.public_key)

Returns:
str: address
"""
@classmethod
def from_passphrase(cls, passphrase: str) -> str:
"""Get an address from passphrase

public_key_bytes = PublicKey(bytes.fromhex(public_key)).format(compressed=False)[1:]
Args:
passphrase (str): passphrase to get address

keccak_hash = keccak.new(
data=bytearray.fromhex(public_key_bytes.hex()),
digest_bits=256,
)
Returns:
str: address
"""
private_key = hashlib.sha256(passphrase.encode()).hexdigest()

return get_checksum_address(unhexlify(keccak_hash.hexdigest()[22:]).hex())
return cls.from_private_key(private_key)

def address_from_private_key(private_key: str) -> str:
"""Get an address from private key
@classmethod
def get_checksum_address(cls, address: str) -> str:
"""Get checksum address

Args:
private_key (string): private key to get address
Args:
address (str): address to get checksum

Returns:
str: address
"""
private_key_object = PrivateKey.from_hex(private_key)
Returns:
str: checksum address
"""
address = address.lower()

return address_from_public_key(private_key_object.public_key.format(compressed=False).hex())
chars = list(address[2:])

def address_from_passphrase(passphrase: str) -> str:
"""Get an address from passphrase
expanded = bytearray(40)
for i in range(40):
expanded[i] = ord(chars[i])

Args:
passphrase (str): passphrase to get address
hashed = keccak.new(data=bytes(expanded), digest_bits=256).digest()

Returns:
str: address
"""
private_key = hashlib.sha256(passphrase.encode()).hexdigest()
for i in range(0, 40, 2):
if (hashed[i >> 1] >> 4) >= 8:
chars[i] = chars[i].upper()
if (hashed[i >> 1] & 0x0F) >= 8:
chars[i + 1] = chars[i + 1].upper()

return address_from_private_key(private_key)
return "0x" + ''.join(chars)
6 changes: 2 additions & 4 deletions crypto/transactions/types/abstract_transaction.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import json
from typing import Optional

from crypto.configuration.network import get_network
from crypto.enums.constants import Constants
from crypto.enums.contract_abi_type import ContractAbiType
from crypto.identity.address import address_from_public_key
from crypto.identity.address import Address
from crypto.identity.private_key import PrivateKey
from crypto.utils.transaction_utils import TransactionUtils
from coincurve import PublicKey
from crypto.utils.abi_decoder import AbiDecoder

class AbstractTransaction:
def __init__(self, data: dict):
Expand Down Expand Up @@ -50,7 +48,7 @@ def recover_sender(self):
hash_ = bytes.fromhex(self.hash(skip_signature=True))
public_key = self.get_public_key(signature_with_recid, hash_)
self.data['senderPublicKey'] = public_key.format().hex()
self.data['senderAddress'] = address_from_public_key(self.data['senderPublicKey'])
self.data['senderAddress'] = Address.from_public_key(self.data['senderPublicKey'])

def verify(self) -> bool:
signature_with_recid = self.get_signature()
Expand Down
5 changes: 2 additions & 3 deletions crypto/utils/abi_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
import json
import os
import re
from binascii import unhexlify
from typing import Optional
from Cryptodome.Hash import keccak
from crypto.enums.contract_abi_type import ContractAbiType
from crypto.identity.address import get_checksum_address
from crypto.identity.address import Address


class AbiBase:
Expand Down Expand Up @@ -38,7 +37,7 @@ def strip_hex_prefix(self, hex_str):

def is_valid_address(self, address):
# Compute the checksum address and compare
computed_checksum_address = get_checksum_address(address.lower())
computed_checksum_address = Address.get_checksum_address(address.lower())

return address.lower() == computed_checksum_address.lower()

Expand Down
4 changes: 2 additions & 2 deletions crypto/utils/abi_decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from crypto.utils.abi_base import AbiBase
import binascii
import re
from crypto.identity.address import get_checksum_address
from crypto.identity.address import Address


class AbiDecoder(AbiBase):
Expand Down Expand Up @@ -88,7 +88,7 @@ def decode_address(bytes_data, offset):
data = bytes_data[offset:offset+32]
address_bytes = data[12:32]
address = '0x' + address_bytes.hex()
address = get_checksum_address(address)
address = Address.get_checksum_address(address)

return address, 32

Expand Down
11 changes: 4 additions & 7 deletions tests/identity/test_address.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import pytest
from crypto.identity.address import (
address_from_passphrase, address_from_private_key, address_from_public_key
)
from crypto.identity.address import Address

def test_address_from_public_key(identity):
address = address_from_public_key(identity['data']['public_key'])
address = Address.from_public_key(identity['data']['public_key'])
assert address == identity['data']['address']


def test_address_from_private_key(identity):
address = address_from_private_key(identity['data']['private_key'])
address = Address.from_private_key(identity['data']['private_key'])
assert address == identity['data']['address']


def test_address_from_passphrase(identity):
address = address_from_passphrase(identity['passphrase'])
address = Address.from_passphrase(identity['passphrase'])
assert address == identity['data']['address']