mirror of https://github.com/nucypher/nucypher.git
Enrico uses a web3 wallet to encrypt-then-sign.
parent
243448d015
commit
783f2dcd76
|
@ -81,6 +81,7 @@ from nucypher.blockchain.eth.registry import (
|
||||||
BaseContractRegistry,
|
BaseContractRegistry,
|
||||||
InMemoryContractRegistry,
|
InMemoryContractRegistry,
|
||||||
)
|
)
|
||||||
|
from nucypher.blockchain.eth.signers import Signer
|
||||||
from nucypher.blockchain.eth.signers.software import Web3Signer
|
from nucypher.blockchain.eth.signers.software import Web3Signer
|
||||||
from nucypher.characters.banners import (
|
from nucypher.characters.banners import (
|
||||||
ALICE_BANNER,
|
ALICE_BANNER,
|
||||||
|
@ -1457,9 +1458,14 @@ class Enrico:
|
||||||
|
|
||||||
banner = ENRICO_BANNER
|
banner = ENRICO_BANNER
|
||||||
|
|
||||||
def __init__(self, encrypting_key: Union[PublicKey, DkgPublicKey]):
|
def __init__(
|
||||||
|
self,
|
||||||
|
encrypting_key: Union[PublicKey, DkgPublicKey],
|
||||||
|
signer: Optional[Signer] = None,
|
||||||
|
):
|
||||||
|
self.signer = signer
|
||||||
self.signing_power = SigningPower()
|
self.signing_power = SigningPower()
|
||||||
self._policy_pubkey = encrypting_key
|
self._encrypting_key = encrypting_key
|
||||||
self.log = Logger(f"{self.__class__.__name__}-{encrypting_key}")
|
self.log = Logger(f"{self.__class__.__name__}-{encrypting_key}")
|
||||||
self.log.info(self.banner.format(encrypting_key))
|
self.log.info(self.banner.format(encrypting_key))
|
||||||
|
|
||||||
|
@ -1477,20 +1483,27 @@ class Enrico:
|
||||||
return message_kit
|
return message_kit
|
||||||
|
|
||||||
def encrypt_for_dkg(
|
def encrypt_for_dkg(
|
||||||
self, plaintext: bytes, conditions: Lingo
|
self,
|
||||||
|
plaintext: bytes,
|
||||||
|
conditions: Lingo,
|
||||||
) -> ThresholdMessageKit:
|
) -> ThresholdMessageKit:
|
||||||
|
if not self.signer:
|
||||||
|
raise TypeError("This Enrico doesn't have a signer.")
|
||||||
|
|
||||||
validate_condition_lingo(conditions)
|
validate_condition_lingo(conditions)
|
||||||
conditions_json = json.dumps(conditions)
|
conditions_json = json.dumps(conditions)
|
||||||
access_conditions = Conditions(conditions_json)
|
access_conditions = Conditions(conditions_json)
|
||||||
|
|
||||||
|
# encrypt for DKG
|
||||||
ciphertext, auth_data = encrypt_for_dkg(
|
ciphertext, auth_data = encrypt_for_dkg(
|
||||||
plaintext, self.policy_pubkey, access_conditions
|
plaintext, self.policy_pubkey, access_conditions
|
||||||
)
|
)
|
||||||
|
|
||||||
# authentication for AllowLogic
|
# authentication message for TACo
|
||||||
# TODO Replace with `Signer` to be passed as parameter
|
|
||||||
header_hash = keccak_digest(bytes(ciphertext.header))
|
header_hash = keccak_digest(bytes(ciphertext.header))
|
||||||
authorization = self.signing_power.keypair.sign(header_hash).to_be_bytes()
|
authorization = self.signer.sign_message(
|
||||||
|
message=header_hash, account=self.signer.accounts[0]
|
||||||
|
)
|
||||||
|
|
||||||
return ThresholdMessageKit(
|
return ThresholdMessageKit(
|
||||||
ciphertext=ciphertext,
|
ciphertext=ciphertext,
|
||||||
|
@ -1509,8 +1522,8 @@ class Enrico:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def policy_pubkey(self):
|
def policy_pubkey(self):
|
||||||
if not self._policy_pubkey:
|
if not self._encrypting_key:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"This Enrico doesn't know which policy encrypting key he used. Oh well."
|
"This Enrico doesn't know which policy encrypting key he used. Oh well."
|
||||||
)
|
)
|
||||||
return self._policy_pubkey
|
return self._encrypting_key
|
||||||
|
|
|
@ -2,6 +2,7 @@ import pytest
|
||||||
import pytest_twisted
|
import pytest_twisted
|
||||||
from twisted.internet.threads import deferToThread
|
from twisted.internet.threads import deferToThread
|
||||||
|
|
||||||
|
from nucypher.blockchain.eth.signers.software import Web3Signer
|
||||||
from nucypher.blockchain.eth.trackers.dkg import EventScannerTask
|
from nucypher.blockchain.eth.trackers.dkg import EventScannerTask
|
||||||
from nucypher.characters.lawful import Enrico
|
from nucypher.characters.lawful import Enrico
|
||||||
from nucypher.policy.conditions.lingo import ConditionLingo
|
from nucypher.policy.conditions.lingo import ConditionLingo
|
||||||
|
@ -134,9 +135,12 @@ def test_ursula_ritualist(
|
||||||
# prepare message and conditions
|
# prepare message and conditions
|
||||||
plaintext = PLAINTEXT.encode()
|
plaintext = PLAINTEXT.encode()
|
||||||
|
|
||||||
|
# create Enrico
|
||||||
|
signer = Web3Signer(client=testerchain.client)
|
||||||
|
enrico = Enrico(encrypting_key=encrypting_key, signer=signer)
|
||||||
|
|
||||||
# encrypt
|
# encrypt
|
||||||
# print(f'encrypting for DKG with key {bytes(encrypting_key.to_bytes()).hex()}')
|
print(f"encrypting for DKG with key {bytes(encrypting_key).hex()}")
|
||||||
enrico = Enrico(encrypting_key=encrypting_key)
|
|
||||||
threshold_message_kit = enrico.encrypt_for_dkg(
|
threshold_message_kit = enrico.encrypt_for_dkg(
|
||||||
plaintext=plaintext, conditions=CONDITIONS
|
plaintext=plaintext, conditions=CONDITIONS
|
||||||
)
|
)
|
||||||
|
|
|
@ -60,6 +60,7 @@ def test_character_transacting_power_signing(testerchain, test_registry):
|
||||||
restored_dict = restored_transaction.as_dict()
|
restored_dict = restored_transaction.as_dict()
|
||||||
assert to_checksum_address(restored_dict['to']) == transaction_dict['to']
|
assert to_checksum_address(restored_dict['to']) == transaction_dict['to']
|
||||||
|
|
||||||
|
|
||||||
def test_transacting_power_sign_message(testerchain):
|
def test_transacting_power_sign_message(testerchain):
|
||||||
|
|
||||||
# Manually create a TransactingPower
|
# Manually create a TransactingPower
|
||||||
|
|
|
@ -10,6 +10,7 @@ from twisted.internet.threads import deferToThread
|
||||||
from web3.datastructures import AttributeDict
|
from web3.datastructures import AttributeDict
|
||||||
|
|
||||||
from nucypher.blockchain.eth.agents import CoordinatorAgent
|
from nucypher.blockchain.eth.agents import CoordinatorAgent
|
||||||
|
from nucypher.blockchain.eth.signers.software import Web3Signer
|
||||||
from nucypher.characters.lawful import Enrico, Ursula
|
from nucypher.characters.lawful import Enrico, Ursula
|
||||||
from nucypher.policy.conditions.lingo import ConditionLingo
|
from nucypher.policy.conditions.lingo import ConditionLingo
|
||||||
from tests.constants import TESTERCHAIN_CHAIN_ID
|
from tests.constants import TESTERCHAIN_CHAIN_ID
|
||||||
|
@ -116,6 +117,7 @@ def execute_round_2(ritual_id: int, cohort: List[Ursula]):
|
||||||
ursula.ritual_tracker._handle_ritual_event(event, get_block_when=lambda x: event)
|
ursula.ritual_tracker._handle_ritual_event(event, get_block_when=lambda x: event)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("mock_sign_message")
|
||||||
@pytest.mark.parametrize('dkg_size, ritual_id, variant', PARAMS)
|
@pytest.mark.parametrize('dkg_size, ritual_id, variant', PARAMS)
|
||||||
@pytest_twisted.inlineCallbacks()
|
@pytest_twisted.inlineCallbacks()
|
||||||
def test_ursula_ritualist(
|
def test_ursula_ritualist(
|
||||||
|
@ -195,9 +197,12 @@ def test_ursula_ritualist(
|
||||||
# prepare message and conditions
|
# prepare message and conditions
|
||||||
plaintext = PLAINTEXT.encode()
|
plaintext = PLAINTEXT.encode()
|
||||||
|
|
||||||
|
# create Enrico
|
||||||
|
signer = Web3Signer(client=testerchain.client)
|
||||||
|
enrico = Enrico(encrypting_key=encrypting_key, signer=signer)
|
||||||
|
|
||||||
# encrypt
|
# encrypt
|
||||||
# print(f'encrypting for DKG with key {bytes(encrypting_key.to_bytes()).hex()}')
|
print(f"encrypting for DKG with key {bytes(encrypting_key).hex()}")
|
||||||
enrico = Enrico(encrypting_key=encrypting_key)
|
|
||||||
threshold_message_kit = enrico.encrypt_for_dkg(
|
threshold_message_kit = enrico.encrypt_for_dkg(
|
||||||
plaintext=plaintext, conditions=CONDITIONS
|
plaintext=plaintext, conditions=CONDITIONS
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from nucypher.blockchain.eth.signers.software import Web3Signer
|
||||||
from nucypher.characters.chaotic import (
|
from nucypher.characters.chaotic import (
|
||||||
NiceGuyEddie,
|
NiceGuyEddie,
|
||||||
ThisBobAlwaysDecrypts,
|
ThisBobAlwaysDecrypts,
|
||||||
|
@ -14,10 +15,11 @@ from tests.constants import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _attempt_decryption(BobClass, plaintext):
|
def _attempt_decryption(BobClass, plaintext, testerchain):
|
||||||
trinket = 80 # Doens't matter.
|
trinket = 80 # Doens't matter.
|
||||||
|
|
||||||
enrico = NiceGuyEddie(encrypting_key=trinket)
|
signer = Web3Signer(client=testerchain.client)
|
||||||
|
enrico = NiceGuyEddie(encrypting_key=trinket, signer=signer)
|
||||||
bob = BobClass(
|
bob = BobClass(
|
||||||
registry=MOCK_REGISTRY_FILEPATH,
|
registry=MOCK_REGISTRY_FILEPATH,
|
||||||
domain="lynx",
|
domain="lynx",
|
||||||
|
@ -46,13 +48,15 @@ def _attempt_decryption(BobClass, plaintext):
|
||||||
return decrypted_cleartext
|
return decrypted_cleartext
|
||||||
|
|
||||||
|
|
||||||
def test_user_controls_success():
|
@pytest.mark.usefixtures("mock_sign_message")
|
||||||
|
def test_user_controls_success(testerchain):
|
||||||
plaintext = b"ever thus to deadbeats"
|
plaintext = b"ever thus to deadbeats"
|
||||||
result = _attempt_decryption(ThisBobAlwaysDecrypts, plaintext)
|
result = _attempt_decryption(ThisBobAlwaysDecrypts, plaintext, testerchain)
|
||||||
assert bytes(result) == bytes(plaintext)
|
assert bytes(result) == bytes(plaintext)
|
||||||
|
|
||||||
|
|
||||||
def test_user_controls_failure():
|
@pytest.mark.usefixtures("mock_sign_message")
|
||||||
|
def test_user_controls_failure(testerchain):
|
||||||
plaintext = b"ever thus to deadbeats"
|
plaintext = b"ever thus to deadbeats"
|
||||||
with pytest.raises(Ursula.NotEnoughUrsulas):
|
with pytest.raises(Ursula.NotEnoughUrsulas):
|
||||||
_ = _attempt_decryption(ThisBobAlwaysFails, plaintext)
|
_ = _attempt_decryption(ThisBobAlwaysFails, plaintext, testerchain)
|
||||||
|
|
|
@ -151,6 +151,7 @@ def test_tls_hosting_certificate_remains_the_same(temp_dir_path, mocker):
|
||||||
recreated_ursula.disenchant()
|
recreated_ursula.disenchant()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("mock_sign_message")
|
||||||
def test_ritualist(temp_dir_path, testerchain, dkg_public_key):
|
def test_ritualist(temp_dir_path, testerchain, dkg_public_key):
|
||||||
keystore = Keystore.generate(
|
keystore = Keystore.generate(
|
||||||
password=INSECURE_DEVELOPMENT_PASSWORD, keystore_dir=temp_dir_path
|
password=INSECURE_DEVELOPMENT_PASSWORD, keystore_dir=temp_dir_path
|
||||||
|
@ -186,11 +187,15 @@ def test_ritualist(temp_dir_path, testerchain, dkg_public_key):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# create enrico
|
||||||
|
signer = Web3Signer(client=testerchain.client)
|
||||||
|
enrico = Enrico(encrypting_key=dkg_public_key, signer=signer)
|
||||||
|
|
||||||
# encrypt
|
# encrypt
|
||||||
enrico = Enrico(encrypting_key=dkg_public_key)
|
|
||||||
threshold_message_kit = enrico.encrypt_for_dkg(
|
threshold_message_kit = enrico.encrypt_for_dkg(
|
||||||
plaintext=plaintext, conditions=CONDITIONS
|
plaintext=plaintext, conditions=CONDITIONS
|
||||||
)
|
)
|
||||||
|
|
||||||
decryption_request = ThresholdDecryptionRequest(
|
decryption_request = ThresholdDecryptionRequest(
|
||||||
ritual_id=ritual_id,
|
ritual_id=ritual_id,
|
||||||
variant=FerveoVariant.Simple,
|
variant=FerveoVariant.Simple,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Iterable, Optional
|
from typing import Iterable, Optional
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ from nucypher.blockchain.eth.interfaces import (
|
||||||
from nucypher.blockchain.eth.networks import NetworksInventory
|
from nucypher.blockchain.eth.networks import NetworksInventory
|
||||||
from nucypher.blockchain.eth.registry import InMemoryContractRegistry
|
from nucypher.blockchain.eth.registry import InMemoryContractRegistry
|
||||||
from nucypher.blockchain.eth.signers import KeystoreSigner
|
from nucypher.blockchain.eth.signers import KeystoreSigner
|
||||||
|
from nucypher.blockchain.eth.signers.software import Web3Signer
|
||||||
from nucypher.characters.lawful import Ursula
|
from nucypher.characters.lawful import Ursula
|
||||||
from nucypher.cli.types import ChecksumAddress
|
from nucypher.cli.types import ChecksumAddress
|
||||||
from nucypher.config.characters import UrsulaConfiguration
|
from nucypher.config.characters import UrsulaConfiguration
|
||||||
|
@ -59,6 +61,14 @@ def mock_sample_reservoir(testerchain, mock_contract_agency):
|
||||||
mock_agent.get_staking_provider_reservoir = mock_reservoir
|
mock_agent.get_staking_provider_reservoir = mock_reservoir
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def mock_sign_message(mocker):
|
||||||
|
mocked_sign_message = mocker.patch.object(
|
||||||
|
Web3Signer, "sign_message", return_value=os.urandom(32)
|
||||||
|
)
|
||||||
|
return mocked_sign_message
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function", autouse=True)
|
@pytest.fixture(scope="function", autouse=True)
|
||||||
def mock_application_agent(
|
def mock_application_agent(
|
||||||
testerchain, application_economics, mock_contract_agency, mocker
|
testerchain, application_economics, mock_contract_agency, mocker
|
||||||
|
|
|
@ -7,7 +7,7 @@ from typing import Union
|
||||||
|
|
||||||
from hexbytes import HexBytes
|
from hexbytes import HexBytes
|
||||||
|
|
||||||
from nucypher.blockchain.eth.clients import EthereumClient
|
from nucypher.blockchain.eth.clients import EthereumTesterClient
|
||||||
from nucypher.blockchain.eth.networks import NetworksInventory
|
from nucypher.blockchain.eth.networks import NetworksInventory
|
||||||
from nucypher.blockchain.eth.registry import (
|
from nucypher.blockchain.eth.registry import (
|
||||||
BaseContractRegistry,
|
BaseContractRegistry,
|
||||||
|
@ -82,7 +82,7 @@ class MockBlockchain(TesterBlockchain):
|
||||||
return self.FAKE_RECEIPT
|
return self.FAKE_RECEIPT
|
||||||
|
|
||||||
|
|
||||||
class MockEthereumClient(EthereumClient):
|
class MockEthereumClient(EthereumTesterClient):
|
||||||
|
|
||||||
def __init__(self, w3):
|
def __init__(self, w3):
|
||||||
super().__init__(w3=w3, node_technology=None, version=None, platform=None, backend=None)
|
super().__init__(w3=w3, node_technology=None, version=None, platform=None, backend=None)
|
||||||
|
|
Loading…
Reference in New Issue