diff --git a/nucypher/blockchain/economics.py b/nucypher/blockchain/economics.py
index 34db922c1..5dd20cb8f 100644
--- a/nucypher/blockchain/economics.py
+++ b/nucypher/blockchain/economics.py
@@ -177,7 +177,8 @@ class SlashingEconomics:
reward_coefficient = 2
@property
- def deployment_parameters(self):
+ def deployment_parameters(self) -> Tuple[int, ...]:
+ """Cast coefficient attributes to uint256 compatible type for solidity+EVM"""
deployment_parameters = [
self.algorithm_sha256,
@@ -187,4 +188,4 @@ class SlashingEconomics:
self.reward_coefficient
]
- return deployment_parameters
+ return tuple(map(int, deployment_parameters))
diff --git a/tests/blockchain/eth/contracts/integration/test_intercontract_integration.py b/tests/blockchain/eth/contracts/integration/test_intercontract_integration.py
index b6d675215..1a8ca37cb 100644
--- a/tests/blockchain/eth/contracts/integration/test_intercontract_integration.py
+++ b/tests/blockchain/eth/contracts/integration/test_intercontract_integration.py
@@ -18,21 +18,21 @@ along with nucypher. If not, see .
import os
-import coincurve
import pytest
-from cryptography.hazmat.primitives.asymmetric import ec
+from cryptography.hazmat.backends.openssl import backend
+from cryptography.hazmat.primitives import hashes
from eth_tester.exceptions import TransactionFailed
from eth_utils import to_canonical_address
from web3.contract import Contract
-from nucypher.blockchain.eth.token import NU
-from nucypher.policy.models import IndisputableEvidence
from umbral import pre
from umbral.curvebn import CurveBN
from umbral.keys import UmbralPrivateKey
-from umbral.signing import Signer, Signature
-from cryptography.hazmat.backends.openssl import backend
-from cryptography.hazmat.primitives import hashes
+from umbral.signing import Signer
+
+from nucypher.blockchain.eth.token import NU
+from nucypher.crypto.utils import get_signature_recovery_value
+from nucypher.policy.models import IndisputableEvidence
VALUE_FIELD = 0
@@ -46,12 +46,6 @@ policy_manager_secret = os.urandom(SECRET_LENGTH)
user_escrow_secret = os.urandom(SECRET_LENGTH)
adjudicator_secret = os.urandom(SECRET_LENGTH)
-ALGORITHM_SHA256 = 1
-BASE_PENALTY = 300
-PENALTY_HISTORY_COEFFICIENT = 10
-PERCENTAGE_PENALTY_COEFFICIENT = 2
-REWARD_COEFFICIENT = 2
-
@pytest.fixture()
def token(testerchain):
@@ -109,7 +103,7 @@ def policy_manager(testerchain, escrow):
@pytest.fixture()
-def adjudicator(testerchain, escrow):
+def adjudicator(testerchain, escrow, slashing_economics):
escrow, _ = escrow
creator = testerchain.interface.w3.eth.accounts[0]
@@ -119,11 +113,8 @@ def adjudicator(testerchain, escrow):
contract, _ = testerchain.interface.deploy_contract(
'MiningAdjudicator',
escrow.address,
- ALGORITHM_SHA256,
- BASE_PENALTY,
- PENALTY_HISTORY_COEFFICIENT,
- PERCENTAGE_PENALTY_COEFFICIENT,
- REWARD_COEFFICIENT)
+ *slashing_economics.deployment_parameters)
+
dispatcher, _ = testerchain.interface.deploy_contract('Dispatcher', contract.address, secret_hash)
# Wrap dispatcher contract
@@ -140,26 +131,8 @@ def adjudicator(testerchain, escrow):
# TODO: Obtain real re-encryption metadata. Maybe constructing a WorkOrder and obtaining a response.
# TODO organize support functions
+# TODO: Repeated method in estimate_gas
def generate_args_for_slashing(testerchain, miner):
- def sign_data(data, umbral_privkey):
- umbral_pubkey_bytes = umbral_privkey.get_pubkey().to_bytes(is_compressed=False)
-
- # Prepare hash of the data
- hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
- hash_ctx.update(data)
- data_hash = hash_ctx.finalize()
-
- # Sign data and calculate recoverable signature
- cryptography_priv_key = umbral_privkey.to_cryptography_privkey()
- signature_der_bytes = cryptography_priv_key.sign(data, ec.ECDSA(hashes.SHA256()))
- signature = Signature.from_bytes(signature_der_bytes, der_encoded=True)
- recoverable_signature = bytes(signature) + bytes([0])
- pubkey_bytes = coincurve.PublicKey.from_signature_and_message(recoverable_signature, data_hash, hasher=None) \
- .format(compressed=False)
- if pubkey_bytes != umbral_pubkey_bytes:
- recoverable_signature = bytes(signature) + bytes([1])
- return recoverable_signature
-
delegating_privkey = UmbralPrivateKey.gen_key()
_symmetric_key, capsule = pre._encapsulate(delegating_privkey.get_pubkey())
signing_privkey = UmbralPrivateKey.gen_key()
@@ -174,19 +147,34 @@ def generate_args_for_slashing(testerchain, miner):
sign_delegating_key=False,
sign_receiving_key=False)
capsule.set_correctness_keys(delegating_privkey.get_pubkey(), pub_key_bob, signing_privkey.get_pubkey())
- cfrag = pre.reencrypt(kfrags[0], capsule, metadata=os.urandom(34))
- capsule_bytes = capsule.to_bytes()
- # Corrupt proof
- cfrag.proof.bn_sig = CurveBN.gen_rand(capsule.params.curve)
- cfrag_bytes = cfrag.to_bytes()
- hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
- hash_ctx.update(capsule_bytes + cfrag_bytes)
- data_hash = hash_ctx.finalize()
- requester_umbral_private_key = UmbralPrivateKey.gen_key()
- requester_umbral_public_key_bytes = requester_umbral_private_key.get_pubkey().to_bytes(is_compressed=False)
- capsule_signature_by_requester = sign_data(capsule_bytes, requester_umbral_private_key)
+
miner_umbral_private_key = UmbralPrivateKey.gen_key()
- miner_umbral_public_key_bytes = miner_umbral_private_key.get_pubkey().to_bytes(is_compressed=False)
+ ursula_pubkey = miner_umbral_private_key.get_pubkey()
+ ursula_pubkey_bytes = ursula_pubkey.to_bytes(is_compressed=False)[1:]
+ specification = bytes(capsule) + ursula_pubkey_bytes + bytes(20) + bytes(32)
+
+ ursulas_signer = Signer(miner_umbral_private_key)
+ bobs_signer = Signer(priv_key_bob)
+ task_signature = bytes(bobs_signer(specification))
+
+ metadata = bytes(ursulas_signer(task_signature))
+
+ cfrag = pre.reencrypt(kfrags[0], capsule, metadata=metadata)
+ cfrag.proof.bn_sig = CurveBN.gen_rand(capsule.params.curve)
+
+ cfrag_signature = bytes(ursulas_signer(bytes(cfrag)))
+
+ bob_pubkey_bytes = pub_key_bob.to_bytes(is_compressed=False)[1:]
+
+ cfrag_signature_v = get_signature_recovery_value(message=bytes(cfrag),
+ signature=cfrag_signature,
+ public_key=ursula_pubkey)
+ task_signature_v = get_signature_recovery_value(message=task_signature,
+ signature=metadata,
+ public_key=ursula_pubkey)
+ recovery_values = cfrag_signature_v + task_signature_v
+
+ miner_umbral_public_key_bytes = miner_umbral_private_key.get_pubkey().to_bytes(is_compressed=False)[1:]
# Sign Umbral public key using eth-key
hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
hash_ctx.update(miner_umbral_public_key_bytes)
@@ -195,16 +183,19 @@ def generate_args_for_slashing(testerchain, miner):
sig_key = testerchain.interface.provider.ethereum_tester.backend._key_lookup[address]
signed_miner_umbral_public_key = bytes(sig_key.sign_msg_hash(miner_umbral_public_key_hash))
- capsule_signature_by_requester_and_miner = sign_data(capsule_signature_by_requester, miner_umbral_private_key)
- cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)
evidence = IndisputableEvidence(capsule, cfrag, ursula=None)
evidence_data = evidence.precompute_values()
- return data_hash, (capsule_bytes,
- capsule_signature_by_requester,
- capsule_signature_by_requester_and_miner,
- cfrag_bytes,
- cfrag_signature_by_miner,
- requester_umbral_public_key_bytes,
+
+ hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
+ hash_ctx.update(bytes(capsule) + bytes(cfrag))
+ data_hash = hash_ctx.finalize()
+
+ return data_hash, (bytes(capsule),
+ bytes(cfrag),
+ cfrag_signature,
+ task_signature,
+ recovery_values,
+ bob_pubkey_bytes,
miner_umbral_public_key_bytes,
signed_miner_umbral_public_key,
evidence_data)
@@ -272,7 +263,7 @@ def execute_multisig_transaction(testerchain, multisig, accounts, tx):
@pytest.mark.slow
-def test_all(testerchain, token, escrow, policy_manager, adjudicator, user_escrow_proxy, multisig):
+def test_all(testerchain, token, escrow, policy_manager, adjudicator, user_escrow_proxy, multisig, slashing_economics):
# Travel to the start of the next period to prevent problems with unexpected overflow first period
testerchain.time_travel(hours=1)
@@ -780,19 +771,22 @@ def test_all(testerchain, token, escrow, policy_manager, adjudicator, user_escro
total_lock = escrow.functions.lockedPerPeriod(period).call()
alice1_balance = token.functions.balanceOf(alice1).call()
+ algorithm_sha256, base_penalty, *coefficients = slashing_economics.deployment_parameters
+ penalty_history_coefficient, percentage_penalty_coefficient, reward_coefficient = coefficients
+
data_hash, slashing_args = generate_args_for_slashing(testerchain, ursula1)
assert not adjudicator.functions.evaluatedCFrags(data_hash).call()
tx = adjudicator.functions.evaluateCFrag(*slashing_args).transact({'from': alice1})
testerchain.wait_for_receipt(tx)
assert adjudicator.functions.evaluatedCFrags(data_hash).call()
- assert tokens_amount - BASE_PENALTY == escrow.functions.minerInfo(ursula1).call()[VALUE_FIELD]
+ assert tokens_amount - base_penalty == escrow.functions.minerInfo(ursula1).call()[VALUE_FIELD]
assert previous_lock == escrow.functions.getLockedTokensInPast(ursula1, 1).call()
assert lock == escrow.functions.getLockedTokens(ursula1).call()
assert next_lock == escrow.functions.getLockedTokens(ursula1, 1).call()
assert total_previous_lock == escrow.functions.lockedPerPeriod(period - 1).call()
assert total_lock == escrow.functions.lockedPerPeriod(period).call()
assert 0 == escrow.functions.lockedPerPeriod(period + 1).call()
- assert alice1_balance + BASE_PENALTY / REWARD_COEFFICIENT == token.functions.balanceOf(alice1).call()
+ assert alice1_balance + base_penalty / reward_coefficient == token.functions.balanceOf(alice1).call()
# Slash part of the one sub stake
tokens_amount = escrow.functions.minerInfo(ursula2).call()[VALUE_FIELD]
@@ -807,14 +801,14 @@ def test_all(testerchain, token, escrow, policy_manager, adjudicator, user_escro
tx = adjudicator.functions.evaluateCFrag(*slashing_args).transact({'from': alice1})
testerchain.wait_for_receipt(tx)
assert adjudicator.functions.evaluatedCFrags(data_hash).call()
- assert lock - BASE_PENALTY == escrow.functions.minerInfo(ursula2).call()[VALUE_FIELD]
+ assert lock - base_penalty == escrow.functions.minerInfo(ursula2).call()[VALUE_FIELD]
assert previous_lock == escrow.functions.getLockedTokensInPast(ursula2, 1).call()
- assert lock - BASE_PENALTY == escrow.functions.getLockedTokens(ursula2).call()
- assert next_lock - BASE_PENALTY == escrow.functions.getLockedTokens(ursula2, 1).call()
+ assert lock - base_penalty == escrow.functions.getLockedTokens(ursula2).call()
+ assert next_lock - base_penalty == escrow.functions.getLockedTokens(ursula2, 1).call()
assert total_previous_lock == escrow.functions.lockedPerPeriod(period - 1).call()
- assert total_lock - BASE_PENALTY == escrow.functions.lockedPerPeriod(period).call()
+ assert total_lock - base_penalty == escrow.functions.lockedPerPeriod(period).call()
assert 0 == escrow.functions.lockedPerPeriod(period + 1).call()
- assert alice1_balance + BASE_PENALTY == token.functions.balanceOf(alice1).call()
+ assert alice1_balance + base_penalty == token.functions.balanceOf(alice1).call()
# Upgrade the adjudicator
# Deploy the same contract as the second version
@@ -822,11 +816,7 @@ def test_all(testerchain, token, escrow, policy_manager, adjudicator, user_escro
adjudicator_v2, _ = testerchain.interface.deploy_contract(
'MiningAdjudicator',
escrow.address,
- ALGORITHM_SHA256,
- BASE_PENALTY,
- PENALTY_HISTORY_COEFFICIENT,
- PERCENTAGE_PENALTY_COEFFICIENT,
- REWARD_COEFFICIENT)
+ *slashing_economics.deployment_parameters)
adjudicator_secret2 = os.urandom(SECRET_LENGTH)
adjudicator_secret2_hash = testerchain.interface.w3.keccak(adjudicator_secret2)
# Ursula and Alice can't upgrade library, only owner can
@@ -900,7 +890,7 @@ def test_all(testerchain, token, escrow, policy_manager, adjudicator, user_escro
tx = adjudicator.functions.evaluateCFrag(*slashing_args).transact({'from': alice2})
testerchain.wait_for_receipt(tx)
assert adjudicator.functions.evaluatedCFrags(data_hash).call()
- penalty = (2 * BASE_PENALTY + 3 * PENALTY_HISTORY_COEFFICIENT)
+ penalty = (2 * base_penalty + 3 * penalty_history_coefficient)
assert lock - penalty == escrow.functions.minerInfo(ursula1).call()[VALUE_FIELD]
assert previous_lock == escrow.functions.getLockedTokensInPast(ursula1, 1).call()
assert lock - penalty == escrow.functions.getLockedTokens(ursula1).call()
@@ -908,7 +898,7 @@ def test_all(testerchain, token, escrow, policy_manager, adjudicator, user_escro
assert total_previous_lock == escrow.functions.lockedPerPeriod(period - 1).call()
assert total_lock - penalty == escrow.functions.lockedPerPeriod(period).call()
assert 0 == escrow.functions.lockedPerPeriod(period + 1).call()
- assert alice2_balance + penalty / REWARD_COEFFICIENT == token.functions.balanceOf(alice2).call()
+ assert alice2_balance + penalty / reward_coefficient == token.functions.balanceOf(alice2).call()
# Unlock and withdraw all tokens in MinersEscrow
for index in range(9):
diff --git a/tests/blockchain/eth/contracts/main/mining_adjudicator/conftest.py b/tests/blockchain/eth/contracts/main/mining_adjudicator/conftest.py
index 9418c209d..09611e4df 100644
--- a/tests/blockchain/eth/contracts/main/mining_adjudicator/conftest.py
+++ b/tests/blockchain/eth/contracts/main/mining_adjudicator/conftest.py
@@ -34,11 +34,7 @@ def adjudicator_contract(testerchain, escrow, request, slashing_economics):
contract, _ = testerchain.interface.deploy_contract(
'MiningAdjudicator',
escrow.address,
- slashing_economics.algorithm_sha256,
- slashing_economics.base_penalty,
- slashing_economics.penalty_history_coefficient,
- slashing_economics.percentage_penalty_coefficient,
- slashing_economics.reward_coefficient)
+ *slashing_economics.deployment_parameters)
if request.param:
secret = os.urandom(DispatcherDeployer.DISPATCHER_SECRET_LENGTH)
diff --git a/tests/blockchain/eth/contracts/main/mining_adjudicator/test_mining_adjudicator.py b/tests/blockchain/eth/contracts/main/mining_adjudicator/test_mining_adjudicator.py
index 8babf1671..5fd277fc9 100644
--- a/tests/blockchain/eth/contracts/main/mining_adjudicator/test_mining_adjudicator.py
+++ b/tests/blockchain/eth/contracts/main/mining_adjudicator/test_mining_adjudicator.py
@@ -18,24 +18,21 @@ along with nucypher. If not, see .
import os
-import coincurve
import pytest
from cryptography.hazmat.backends.openssl import backend
from cryptography.hazmat.primitives import hashes
-from cryptography.hazmat.primitives.asymmetric import ec
from eth_tester.exceptions import TransactionFailed
-from eth_utils import to_canonical_address, to_checksum_address
+from eth_utils import to_canonical_address
from typing import Tuple
from web3.contract import Contract
from umbral import pre
-from umbral.config import default_params
from umbral.curvebn import CurveBN
from umbral.keys import UmbralPrivateKey
from umbral.point import Point
-from umbral.random_oracles import hash_to_curvebn, ExtendedKeccak
-from umbral.signing import Signature, Signer
+from umbral.signing import Signer
+from nucypher.crypto.utils import get_signature_recovery_value
from nucypher.policy.models import IndisputableEvidence
@@ -45,33 +42,8 @@ secret = (123456).to_bytes(32, byteorder='big')
secret2 = (654321).to_bytes(32, byteorder='big')
-def sign_data(data, umbral_privkey):
- umbral_pubkey_bytes = umbral_privkey.get_pubkey().to_bytes(is_compressed=False)
-
- # Prepare hash of the data
- hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
- hash_ctx.update(data)
- data_hash = hash_ctx.finalize()
-
- # Sign data and calculate recoverable signature
- cryptography_priv_key = umbral_privkey.to_cryptography_privkey()
- signature_der_bytes = cryptography_priv_key.sign(data, ec.ECDSA(hashes.SHA256()))
- signature = Signature.from_bytes(signature_der_bytes, der_encoded=True)
- recoverable_signature = make_recoverable_signature(data_hash, signature, umbral_pubkey_bytes)
- return recoverable_signature
-
-
-def make_recoverable_signature(data_hash, signature, umbral_pubkey_bytes):
- recoverable_signature = bytes(signature) + bytes([0])
- pubkey_bytes = coincurve.PublicKey.from_signature_and_message(recoverable_signature, data_hash, hasher=None) \
- .format(compressed=False)
- if pubkey_bytes != umbral_pubkey_bytes:
- recoverable_signature = bytes(signature) + bytes([1])
- return recoverable_signature
-
-
# TODO: Obtain real re-encryption metadata. Maybe constructing a WorkOrder and obtaining a response.
-def fragments(metadata):
+def mock_ursula_reencrypts(ursula_privkey, corrupt_cfrag: bool = False):
delegating_privkey = UmbralPrivateKey.gen_key()
_symmetric_key, capsule = pre._encapsulate(delegating_privkey.get_pubkey())
signing_privkey = UmbralPrivateKey.gen_key()
@@ -86,8 +58,42 @@ def fragments(metadata):
sign_delegating_key=False,
sign_receiving_key=False)
capsule.set_correctness_keys(delegating_privkey.get_pubkey(), pub_key_bob, signing_privkey.get_pubkey())
+
+ ursula_pubkey = ursula_privkey.get_pubkey()
+ ursula_pubkey_bytes = ursula_pubkey.to_bytes(is_compressed=False)[1:]
+ specification = bytes(capsule) + ursula_pubkey_bytes + bytes(20) + bytes(32)
+
+ ursulas_signer = Signer(ursula_privkey)
+ bobs_signer = Signer(priv_key_bob)
+ task_signature = bytes(bobs_signer(specification))
+
+ metadata = bytes(ursulas_signer(task_signature))
+
cfrag = pre.reencrypt(kfrags[0], capsule, metadata=metadata)
- return capsule, cfrag
+
+ if corrupt_cfrag:
+ cfrag.proof.bn_sig = CurveBN.gen_rand(capsule.params.curve)
+
+ cfrag_signature = bytes(ursulas_signer(bytes(cfrag)))
+
+ bob_pubkey_bytes = pub_key_bob.to_bytes(is_compressed=False)[1:]
+
+ cfrag_signature_v = get_signature_recovery_value(message=bytes(cfrag),
+ signature=cfrag_signature,
+ public_key=ursula_pubkey)
+ task_signature_v = get_signature_recovery_value(message=task_signature,
+ signature=metadata,
+ public_key=ursula_pubkey)
+ recovery_values = cfrag_signature_v + task_signature_v
+
+ return capsule, cfrag, cfrag_signature, task_signature, recovery_values, bob_pubkey_bytes
+
+
+def evaluation_hash(capsule, cfrag):
+ hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
+ hash_ctx.update(bytes(capsule) + bytes(cfrag))
+ data_hash = hash_ctx.finalize()
+ return data_hash
@pytest.mark.slow
@@ -113,7 +119,7 @@ def test_evaluate_cfrag(testerchain, escrow, adjudicator_contract, slashing_econ
# Generate miner's Umbral key
miner_umbral_private_key = UmbralPrivateKey.gen_key()
- miner_umbral_public_key_bytes = miner_umbral_private_key.get_pubkey().to_bytes(is_compressed=False)
+ miner_umbral_public_key_bytes = miner_umbral_private_key.get_pubkey().to_bytes(is_compressed=False)[1:]
# Sign Umbral public key using eth-key
hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
@@ -124,43 +130,28 @@ def test_evaluate_cfrag(testerchain, escrow, adjudicator_contract, slashing_econ
sig_key = provider.ethereum_tester.backend._key_lookup[address]
signed_miner_umbral_public_key = bytes(sig_key.sign_msg_hash(miner_umbral_public_key_hash))
- # Prepare hash of the data
- metadata = os.urandom(33)
- capsule, cfrag = fragments(metadata)
-
+ # Prepare evaluation data
+ capsule, cfrag, *other_stuff = mock_ursula_reencrypts(miner_umbral_private_key)
+ cfrag_signature, task_signature, recovery_values, bob_pubkey_bytes = other_stuff
assert cfrag.verify_correctness(capsule)
- capsule_bytes = capsule.to_bytes()
- cfrag_bytes = cfrag.to_bytes()
-
- # Bob prepares supporting Evidence
+ # Investigator prepares supporting Evidence
evidence = IndisputableEvidence(capsule, cfrag, ursula=None)
evidence_data = evidence.precompute_values()
assert len(evidence_data) == 20 * 32 + 32 + 20 + 1
- hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
- hash_ctx.update(capsule_bytes + cfrag_bytes)
- data_hash = hash_ctx.finalize()
+ data_hash = evaluation_hash(capsule, cfrag)
# This capsule and cFrag are not yet evaluated
assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()
- # Generate requester's Umbral key
- requester_umbral_private_key = UmbralPrivateKey.gen_key()
- requester_umbral_public_key_bytes = requester_umbral_private_key.get_pubkey().to_bytes(is_compressed=False)
-
- # Sign capsule and cFrag
- capsule_signature_by_requester = sign_data(capsule_bytes, requester_umbral_private_key)
- capsule_signature_by_requester_and_miner = sign_data(capsule_signature_by_requester, miner_umbral_private_key)
- cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)
-
# Challenge using good data
- args = (capsule_bytes,
- capsule_signature_by_requester,
- capsule_signature_by_requester_and_miner,
- cfrag_bytes,
- cfrag_signature_by_miner,
- requester_umbral_public_key_bytes,
+ args = (bytes(capsule),
+ bytes(cfrag),
+ cfrag_signature,
+ task_signature,
+ recovery_values,
+ bob_pubkey_bytes,
miner_umbral_public_key_bytes,
signed_miner_umbral_public_key,
evidence_data)
@@ -183,39 +174,36 @@ def test_evaluate_cfrag(testerchain, escrow, adjudicator_contract, slashing_econ
assert investigator == event_args['investigator']
assert event_args['correctness']
+ ###############################
# Test: Don't evaluate miner with data that already was checked
+ ###############################
+ # TODO: be more specific on the expected exception
with pytest.raises((TransactionFailed, ValueError)):
tx = adjudicator_contract.functions.evaluateCFrag(*args).transact()
testerchain.wait_for_receipt(tx)
+ ###############################
# Test: Ursula produces incorrect proof:
- metadata = os.urandom(34)
- capsule, cfrag = fragments(metadata)
- capsule_bytes = capsule.to_bytes()
- # Corrupt proof
- cfrag.proof.bn_sig = CurveBN.gen_rand(capsule.params.curve)
- cfrag_bytes = cfrag.to_bytes()
+ ###############################
+ capsule, cfrag, *other_stuff = mock_ursula_reencrypts(miner_umbral_private_key, corrupt_cfrag=True)
+ cfrag_signature, task_signature, recovery_values, bob_pubkey_bytes = other_stuff
assert not cfrag.verify_correctness(capsule)
- hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
- hash_ctx.update(capsule_bytes + cfrag_bytes)
- data_hash = hash_ctx.finalize()
- capsule_signature_by_requester = sign_data(capsule_bytes, requester_umbral_private_key)
- capsule_signature_by_requester_and_miner = sign_data(capsule_signature_by_requester, miner_umbral_private_key)
- cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)
evidence = IndisputableEvidence(capsule, cfrag, ursula=None)
evidence_data = evidence.precompute_values()
- args = (capsule_bytes,
- capsule_signature_by_requester,
- capsule_signature_by_requester_and_miner,
- cfrag_bytes,
- cfrag_signature_by_miner,
- requester_umbral_public_key_bytes,
+ args = (bytes(capsule),
+ bytes(cfrag),
+ cfrag_signature,
+ task_signature,
+ recovery_values,
+ bob_pubkey_bytes,
miner_umbral_public_key_bytes,
signed_miner_umbral_public_key,
evidence_data)
+ data_hash = evaluation_hash(capsule, cfrag)
assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()
+
tx = adjudicator_contract.functions.evaluateCFrag(*args).transact({'from': investigator})
testerchain.wait_for_receipt(tx)
number_of_evaluations += 1
@@ -243,18 +231,10 @@ def test_evaluate_cfrag(testerchain, escrow, adjudicator_contract, slashing_econ
# Test: Bob produces wrong precomputed data
###############################
- metadata = os.urandom(34)
- capsule, cfrag = fragments(metadata)
- capsule_bytes = capsule.to_bytes()
- cfrag_bytes = cfrag.to_bytes()
+ capsule, cfrag, *other_stuff = mock_ursula_reencrypts(miner_umbral_private_key)
+ cfrag_signature, task_signature, recovery_values, bob_pubkey_bytes = other_stuff
assert cfrag.verify_correctness(capsule)
- hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
- hash_ctx.update(capsule_bytes + cfrag_bytes)
- data_hash = hash_ctx.finalize()
- capsule_signature_by_requester = sign_data(capsule_bytes, requester_umbral_private_key)
- capsule_signature_by_requester_and_miner = sign_data(capsule_signature_by_requester, miner_umbral_private_key)
- cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)
evidence = IndisputableEvidence(capsule, cfrag, ursula=None)
evidence_data = evidence.precompute_values()
@@ -265,16 +245,17 @@ def test_evaluate_cfrag(testerchain, escrow, adjudicator_contract, slashing_econ
evidence_data[32:32+64] = random_point_bytes
evidence_data = bytes(evidence_data)
- args = (capsule_bytes,
- capsule_signature_by_requester,
- capsule_signature_by_requester_and_miner,
- cfrag_bytes,
- cfrag_signature_by_miner,
- requester_umbral_public_key_bytes,
+ args = (bytes(capsule),
+ bytes(cfrag),
+ cfrag_signature,
+ task_signature,
+ recovery_values,
+ bob_pubkey_bytes,
miner_umbral_public_key_bytes,
signed_miner_umbral_public_key,
evidence_data)
+ data_hash = evaluation_hash(capsule, cfrag)
assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()
# Evaluation must fail since Bob precomputed wrong values
@@ -292,34 +273,27 @@ def test_evaluate_cfrag(testerchain, escrow, adjudicator_contract, slashing_econ
# Test: Second violation. Penalty is increased
###############################
- # Prepare hash of the data
- metadata = os.urandom(34)
- capsule, cfrag = fragments(metadata)
- capsule_bytes = capsule.to_bytes()
- # Corrupt proof
- cfrag.proof.bn_sig = CurveBN.gen_rand(capsule.params.curve)
- cfrag_bytes = cfrag.to_bytes()
- hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
- hash_ctx.update(capsule_bytes + cfrag_bytes)
- data_hash = hash_ctx.finalize()
- capsule_signature_by_requester = sign_data(capsule_bytes, requester_umbral_private_key)
- capsule_signature_by_requester_and_miner = sign_data(capsule_signature_by_requester, miner_umbral_private_key)
- cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)
+ capsule, cfrag, *other_stuff = mock_ursula_reencrypts(miner_umbral_private_key, corrupt_cfrag=True)
+ cfrag_signature, task_signature, recovery_values, bob_pubkey_bytes = other_stuff
+
evidence = IndisputableEvidence(capsule, cfrag, ursula=None)
evidence_data = evidence.precompute_values()
- args = [capsule_bytes,
- capsule_signature_by_requester,
- capsule_signature_by_requester_and_miner,
- cfrag_bytes,
- cfrag_signature_by_miner,
- requester_umbral_public_key_bytes,
+ args = (bytes(capsule),
+ bytes(cfrag),
+ cfrag_signature,
+ task_signature,
+ recovery_values,
+ bob_pubkey_bytes,
miner_umbral_public_key_bytes,
signed_miner_umbral_public_key,
- evidence_data]
+ evidence_data)
+
+ data_hash = evaluation_hash(capsule, cfrag)
assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()
worker_stake = escrow.functions.minerInfo(miner).call()[0]
investigator_balance = escrow.functions.rewardInfo(investigator).call()
+
assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()
tx = adjudicator_contract.functions.evaluateCFrag(*args).transact({'from': investigator})
testerchain.wait_for_receipt(tx)
@@ -350,33 +324,27 @@ def test_evaluate_cfrag(testerchain, escrow, adjudicator_contract, slashing_econ
# Test: Third violation. Penalty reaches the maximum allowed
###############################
- # Prepare corrupted data again
- capsule, cfrag = fragments(metadata)
- capsule_bytes = capsule.to_bytes()
- # Corrupt proof
- cfrag.proof.bn_sig = CurveBN.gen_rand(capsule.params.curve)
- cfrag_bytes = cfrag.to_bytes()
- hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
- hash_ctx.update(capsule_bytes + cfrag_bytes)
- data_hash = hash_ctx.finalize()
- capsule_signature_by_requester = sign_data(capsule_bytes, requester_umbral_private_key)
- capsule_signature_by_requester_and_miner = sign_data(capsule_signature_by_requester, miner_umbral_private_key)
- cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)
+ capsule, cfrag, *other_stuff = mock_ursula_reencrypts(miner_umbral_private_key, corrupt_cfrag=True)
+ cfrag_signature, task_signature, recovery_values, bob_pubkey_bytes = other_stuff
+
evidence = IndisputableEvidence(capsule, cfrag, ursula=None)
evidence_data = evidence.precompute_values()
- args = [capsule_bytes,
- capsule_signature_by_requester,
- capsule_signature_by_requester_and_miner,
- cfrag_bytes,
- cfrag_signature_by_miner,
- requester_umbral_public_key_bytes,
+ args = (bytes(capsule),
+ bytes(cfrag),
+ cfrag_signature,
+ task_signature,
+ recovery_values,
+ bob_pubkey_bytes,
miner_umbral_public_key_bytes,
signed_miner_umbral_public_key,
- evidence_data]
+ evidence_data)
+
+ data_hash = evaluation_hash(capsule, cfrag)
+ assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()
worker_stake = escrow.functions.minerInfo(miner).call()[0]
investigator_balance = escrow.functions.rewardInfo(investigator).call()
- assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()
+
tx = adjudicator_contract.functions.evaluateCFrag(*args).transact({'from': investigator})
testerchain.wait_for_receipt(tx)
number_of_evaluations += 1
@@ -406,47 +374,40 @@ def test_evaluate_cfrag(testerchain, escrow, adjudicator_contract, slashing_econ
##############
# Can't evaluate miner using broken signatures
- wrong_args = args[:]
- wrong_args[1] = capsule_signature_by_requester[1:]
+ wrong_args = list(args)
+ wrong_args[2] = cfrag_signature[1:]
with pytest.raises((TransactionFailed, ValueError)):
tx = adjudicator_contract.functions.evaluateCFrag(*wrong_args).transact()
testerchain.wait_for_receipt(tx)
- wrong_args = args[:]
- wrong_args[2] = capsule_signature_by_requester_and_miner[1:]
+
+ wrong_args = list(args)
+ wrong_args[3] = task_signature[1:]
with pytest.raises((TransactionFailed, ValueError)):
tx = adjudicator_contract.functions.evaluateCFrag(*wrong_args).transact()
testerchain.wait_for_receipt(tx)
- wrong_args = args[:]
- wrong_args[4] = cfrag_signature_by_miner[1:]
- with pytest.raises((TransactionFailed, ValueError)):
- tx = adjudicator_contract.functions.evaluateCFrag(*wrong_args).transact()
- testerchain.wait_for_receipt(tx)
- wrong_args = args[:]
+
+ wrong_args = list(args)
wrong_args[7] = signed_miner_umbral_public_key[1:]
with pytest.raises((TransactionFailed, ValueError)):
tx = adjudicator_contract.functions.evaluateCFrag(*wrong_args).transact()
testerchain.wait_for_receipt(tx)
# Can't evaluate miner using wrong keys
- wrong_args = args[:]
- wrong_args[5] = UmbralPrivateKey.gen_key().get_pubkey().to_bytes(is_compressed=False)
+ wrong_args = list(args)
+ wrong_args[5] = UmbralPrivateKey.gen_key().get_pubkey().to_bytes(is_compressed=False)[1:]
with pytest.raises((TransactionFailed, ValueError)):
tx = adjudicator_contract.functions.evaluateCFrag(*wrong_args).transact()
testerchain.wait_for_receipt(tx)
- wrong_args = args[:]
- wrong_args[6] = UmbralPrivateKey.gen_key().get_pubkey().to_bytes(is_compressed=False)
+
+ wrong_args = list(args)
+ wrong_args[6] = UmbralPrivateKey.gen_key().get_pubkey().to_bytes(is_compressed=False)[1:]
with pytest.raises((TransactionFailed, ValueError)):
tx = adjudicator_contract.functions.evaluateCFrag(*wrong_args).transact()
testerchain.wait_for_receipt(tx)
# Can't use signature for another data
- wrong_args = args[:]
- wrong_args[0] = bytes(args[0][0] + 1) + args[0][1:]
- with pytest.raises((TransactionFailed, ValueError)):
- tx = adjudicator_contract.functions.evaluateCFrag(*wrong_args).transact()
- testerchain.wait_for_receipt(tx)
- wrong_args = args[:]
- wrong_args[3] = bytes(args[3][0] + 1) + args[3][1:]
+ wrong_args = list(args)
+ wrong_args[1] = os.urandom(len(bytes(cfrag)))
with pytest.raises((TransactionFailed, ValueError)):
tx = adjudicator_contract.functions.evaluateCFrag(*wrong_args).transact()
testerchain.wait_for_receipt(tx)
@@ -455,7 +416,8 @@ def test_evaluate_cfrag(testerchain, escrow, adjudicator_contract, slashing_econ
address = to_canonical_address(wrong_miner)
sig_key = provider.ethereum_tester.backend._key_lookup[address]
signed_wrong_miner_umbral_public_key = bytes(sig_key.sign_msg_hash(miner_umbral_public_key_hash))
- wrong_args = args[:]
+
+ wrong_args = list(args)
wrong_args[7] = signed_wrong_miner_umbral_public_key
with pytest.raises((TransactionFailed, ValueError)):
tx = adjudicator_contract.functions.evaluateCFrag(*wrong_args).transact()
diff --git a/tests/metrics/estimate_gas.py b/tests/metrics/estimate_gas.py
index bc73d6fa8..61930db2d 100755
--- a/tests/metrics/estimate_gas.py
+++ b/tests/metrics/estimate_gas.py
@@ -18,34 +18,29 @@ You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see .
"""
-import coincurve
+import io
import json
import os
-
-from cryptography.hazmat.primitives.asymmetric import ec
-from eth_utils import to_canonical_address
-
-from nucypher.blockchain.economics import TokenEconomics
-from nucypher.policy.models import IndisputableEvidence, Policy
-from umbral import pre
-from umbral.curvebn import CurveBN
-from umbral.keys import UmbralPrivateKey
-from umbral.signing import Signer, Signature
-
+import re
import time
from os.path import abspath, dirname
-import io
-import re
-
+from eth_utils import to_canonical_address
from cryptography.hazmat.backends.openssl import backend
from cryptography.hazmat.primitives import hashes
from twisted.logger import globalLogPublisher, Logger, jsonFileLogObserver, ILogObserver
from zope.interface import provider
-from nucypher.blockchain.eth.agents import NucypherTokenAgent, MinerAgent, PolicyAgent, MiningAdjudicatorAgent
-from nucypher.utilities.sandbox.blockchain import TesterBlockchain
+from umbral import pre
+from umbral.curvebn import CurveBN
+from umbral.keys import UmbralPrivateKey
+from umbral.signing import Signer
+from nucypher.blockchain.economics import TokenEconomics
+from nucypher.blockchain.eth.agents import NucypherTokenAgent, MinerAgent, PolicyAgent, MiningAdjudicatorAgent
+from nucypher.crypto.utils import get_signature_recovery_value
+from nucypher.policy.models import IndisputableEvidence, Policy
+from nucypher.utilities.sandbox.blockchain import TesterBlockchain
ALGORITHM_SHA256 = 1
TOKEN_ECONOMICS = TokenEconomics()
@@ -121,26 +116,8 @@ class AnalyzeGas:
# TODO organize support functions
+# TODO: Repeated method in test_intercontract_integration
def generate_args_for_slashing(testerchain, miner, corrupt: bool = True):
- def sign_data(data, umbral_privkey):
- umbral_pubkey_bytes = umbral_privkey.get_pubkey().to_bytes(is_compressed=False)
-
- # Prepare hash of the data
- hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
- hash_ctx.update(data)
- data_hash = hash_ctx.finalize()
-
- # Sign data and calculate recoverable signature
- cryptography_priv_key = umbral_privkey.to_cryptography_privkey()
- signature_der_bytes = cryptography_priv_key.sign(data, ec.ECDSA(hashes.SHA256()))
- signature = Signature.from_bytes(signature_der_bytes, der_encoded=True)
- recoverable_signature = bytes(signature) + bytes([0])
- pubkey_bytes = coincurve.PublicKey.from_signature_and_message(recoverable_signature, data_hash, hasher=None) \
- .format(compressed=False)
- if pubkey_bytes != umbral_pubkey_bytes:
- recoverable_signature = bytes(signature) + bytes([1])
- return recoverable_signature
-
delegating_privkey = UmbralPrivateKey.gen_key()
_symmetric_key, capsule = pre._encapsulate(delegating_privkey.get_pubkey())
signing_privkey = UmbralPrivateKey.gen_key()
@@ -155,18 +132,35 @@ def generate_args_for_slashing(testerchain, miner, corrupt: bool = True):
sign_delegating_key=False,
sign_receiving_key=False)
capsule.set_correctness_keys(delegating_privkey.get_pubkey(), pub_key_bob, signing_privkey.get_pubkey())
- cfrag = pre.reencrypt(kfrags[0], capsule, metadata=os.urandom(34))
- capsule_bytes = capsule.to_bytes()
+
+ miner_umbral_private_key = UmbralPrivateKey.gen_key()
+ ursula_pubkey = miner_umbral_private_key.get_pubkey()
+ ursula_pubkey_bytes = ursula_pubkey.to_bytes(is_compressed=False)[1:]
+ specification = bytes(capsule) + ursula_pubkey_bytes + bytes(20) + bytes(32)
+
+ ursulas_signer = Signer(miner_umbral_private_key)
+ bobs_signer = Signer(priv_key_bob)
+ task_signature = bytes(bobs_signer(specification))
+
+ metadata = bytes(ursulas_signer(task_signature))
+
+ cfrag = pre.reencrypt(kfrags[0], capsule, metadata=metadata)
if corrupt:
cfrag.proof.bn_sig = CurveBN.gen_rand(capsule.params.curve)
- cfrag_bytes = cfrag.to_bytes()
- hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
- hash_ctx.update(capsule_bytes + cfrag_bytes)
- requester_umbral_private_key = UmbralPrivateKey.gen_key()
- requester_umbral_public_key_bytes = requester_umbral_private_key.get_pubkey().to_bytes(is_compressed=False)
- capsule_signature_by_requester = sign_data(capsule_bytes, requester_umbral_private_key)
- miner_umbral_private_key = UmbralPrivateKey.gen_key()
- miner_umbral_public_key_bytes = miner_umbral_private_key.get_pubkey().to_bytes(is_compressed=False)
+
+ cfrag_signature = bytes(ursulas_signer(bytes(cfrag)))
+
+ bob_pubkey_bytes = pub_key_bob.to_bytes(is_compressed=False)[1:]
+
+ cfrag_signature_v = get_signature_recovery_value(message=bytes(cfrag),
+ signature=cfrag_signature,
+ public_key=ursula_pubkey)
+ task_signature_v = get_signature_recovery_value(message=task_signature,
+ signature=metadata,
+ public_key=ursula_pubkey)
+ recovery_values = cfrag_signature_v + task_signature_v
+
+ miner_umbral_public_key_bytes = miner_umbral_private_key.get_pubkey().to_bytes(is_compressed=False)[1:]
# Sign Umbral public key using eth-key
hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
hash_ctx.update(miner_umbral_public_key_bytes)
@@ -175,16 +169,15 @@ def generate_args_for_slashing(testerchain, miner, corrupt: bool = True):
sig_key = testerchain.interface.provider.ethereum_tester.backend._key_lookup[address]
signed_miner_umbral_public_key = bytes(sig_key.sign_msg_hash(miner_umbral_public_key_hash))
- capsule_signature_by_requester_and_miner = sign_data(capsule_signature_by_requester, miner_umbral_private_key)
- cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)
evidence = IndisputableEvidence(capsule, cfrag, ursula=None)
evidence_data = evidence.precompute_values()
- return (capsule_bytes,
- capsule_signature_by_requester,
- capsule_signature_by_requester_and_miner,
- cfrag_bytes,
- cfrag_signature_by_miner,
- requester_umbral_public_key_bytes,
+
+ return (bytes(capsule),
+ bytes(cfrag),
+ cfrag_signature,
+ task_signature,
+ recovery_values,
+ bob_pubkey_bytes,
miner_umbral_public_key_bytes,
signed_miner_umbral_public_key,
evidence_data)