Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor signatures #414

Merged
merged 23 commits into from
Apr 14, 2022
Merged
Show file tree
Hide file tree
Changes from 19 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
8 changes: 6 additions & 2 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ jobs:
- name: Run Barge
working-directory: ${{ github.workspace }}/barge
env:
OPERATOR_SERVICE_VERSION: compute_envs
OPERATOR_ENGINE_VERSION: compute_envs
OPERATOR_SERVICE_VERSION: refactor_signatures
CONTRACTS_VERSION: v1.0.0-alpha.28
AQUARIUS_VERSION: refactor_signatures
PROVIDER_VERSION: refactor_signatures
run: |
bash -x start_ocean.sh --no-dashboard 2>&1 --with-rbac --with-provider2 --with-c2d > start_ocean.log &
for i in $(seq 1 150); do
Expand All @@ -47,6 +48,9 @@ jobs:
coverage run --source ocean_provider -m pytest
coverage report
coverage xml
- name: docker logs
run: docker logs ocean_aquarius_1 && docker logs ocean_provider_1 && docker logs ocean_provider2_1 && docker logs ocean_computetodata_1
if: ${{ failure() }}
- name: Publish code coverage
uses: paambaati/[email protected]
env:
Expand Down
68 changes: 50 additions & 18 deletions ocean_provider/utils/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
#
import logging

import eth_keys
from eth_account.account import Account
from eth_account.messages import encode_defunct
alexcos20 marked this conversation as resolved.
Show resolved Hide resolved
from eth_keys import KeyAPI
from eth_keys.backends import NativeECCBackend
from ocean_provider.exceptions import InvalidSignatureError
from ocean_provider.user_nonce import get_nonce
from ocean_provider.utils.basics import get_web3
from web3 import Web3

logger = logging.getLogger(__name__)
keys = KeyAPI(NativeECCBackend)


def verify_signature(signer_address, signature, original_msg, nonce):
Expand All @@ -28,37 +29,68 @@ def verify_signature(signer_address, signature, original_msg, nonce):
raise InvalidSignatureError(msg)

message = f"{original_msg}{str(nonce)}"
address = Account.recover_message(encode_defunct(text=message), signature=signature)
signature_bytes = Web3.toBytes(hexstr=signature)
if signature_bytes[64] == 27:
new_signature = b"".join([signature_bytes[0:64], b"\x00"])
elif signature_bytes[64] == 28:
new_signature = b"".join([signature_bytes[0:64], b"\x01"])
else:
new_signature = signature_bytes

if address.lower() == signer_address.lower():
return True

msg = (
f"Invalid signature {signature} for "
f"ethereum address {signer_address}, message {original_msg} "
f"and nonce {nonce}. Expected: {signer_address.lower()} but got {address.lower()}"
signature = keys.Signature(signature_bytes=new_signature)
message_hash = Web3.solidityKeccak(
["bytes"],
[Web3.toBytes(text=message)],
)
prefix = "\x19Ethereum Signed Message:\n32"
signable_hash = Web3.solidityKeccak(
["bytes", "bytes"], [Web3.toBytes(text=prefix), Web3.toBytes(message_hash)]
)
logger.error(msg)
raise InvalidSignatureError(msg)
vkey = keys.ecdsa_recover(signable_hash, signature)

if Web3.toChecksumAddress(signer_address) != Web3.toChecksumAddress(
vkey.to_address()
):
msg = (
f"Invalid signature {signature} for "
f"ethereum address {signer_address}, message {original_msg} "
f"and nonce {nonce}. Got {vkey.to_address()}"
)
logger.error(msg)
raise InvalidSignatureError(msg)

return True


def get_private_key(wallet):
"""Returns private key of the given wallet"""
pk = wallet.key
if not isinstance(pk, bytes):
pk = Web3.toBytes(hexstr=pk)
return eth_keys.KeyAPI.PrivateKey(pk)
return keys.PrivateKey(pk)


def sign_message(message, wallet):
"""
:param message: str
:param wallet: Wallet instance
:return: `hex` value of the signed message
:return: signature
"""
w3 = get_web3()
signed = w3.eth.account.sign_message(
encode_defunct(text=message), private_key=wallet.key
keys_pk = keys.PrivateKey(wallet.key)
message_hash = Web3.solidityKeccak(
["bytes"],
[Web3.toBytes(text=message)],
)
prefix = "\x19Ethereum Signed Message:\n32"
signable_hash = Web3.solidityKeccak(
["bytes", "bytes"], [Web3.toBytes(text=prefix), Web3.toBytes(message_hash)]
)
signed = keys.ecdsa_sign(message_hash=signable_hash, private_key=keys_pk)

v = str(Web3.toHex(Web3.toBytes(signed.v)))
r = str(Web3.toHex(Web3.toBytes(signed.r).rjust(32, b"\0")))
s = str(Web3.toHex(Web3.toBytes(signed.s).rjust(32, b"\0")))

signature = "0x" + r[2:] + s[2:] + v[2:]

return signed.signature.hex()
return signature
9 changes: 5 additions & 4 deletions ocean_provider/utils/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
from jsonsempai import magic # noqa: F401
from artifacts import ERC721Template
from eth_account.signers.local import LocalAccount
from eth_keys import KeyAPI
from eth_keys.backends import NativeECCBackend
from flask import Response
from ocean_provider.utils.accounts import sign_message
from ocean_provider.utils.basics import get_config, get_provider_wallet, get_web3
Expand All @@ -26,9 +28,11 @@
from ocean_provider.utils.encryption import do_decrypt
from ocean_provider.utils.services import Service
from ocean_provider.utils.url import is_safe_url
from web3 import Web3
from websockets import ConnectionClosed

logger = logging.getLogger(__name__)
keys = KeyAPI(NativeECCBackend)


def get_metadata_url():
Expand Down Expand Up @@ -329,10 +333,7 @@ def sign_for_compute(wallet, owner, job_id=None):
nonce = datetime.utcnow().timestamp()

# prepare consumer signature on did
if job_id:
msg = f"{owner}{job_id}{nonce}"
else:
msg = f"{owner}{nonce}"
msg = f"{owner}{job_id}{nonce}" if job_id else f"{owner}{nonce}"
signature = sign_message(msg, wallet)

return nonce, signature
2 changes: 1 addition & 1 deletion tests/test_compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def test_compute(client, publisher_wallet, consumer_wallet):
tries = 0
while tries < 200:
job_info = get_compute_job_info(client, compute_endpoint, payload)
if job_info["dateFinished"] and int(job_info["dateFinished"]) > 0:
if job_info["dateFinished"] and float(job_info["dateFinished"]) > 0:
break
tries = tries + 1
time.sleep(5)
Expand Down