From a09c3d8858ac692374a26e8c6d618c3717c84ea4 Mon Sep 17 00:00:00 2001 From: jMyles Date: Fri, 21 Sep 2018 21:52:57 +0200 Subject: [PATCH] Reintroducing demo entry modules. --- examples/finnegans-wake-federated.py | 177 +++++++++++++++++++++++++++ examples/run_federated_ursula.py | 81 ++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 examples/finnegans-wake-federated.py create mode 100644 examples/run_federated_ursula.py diff --git a/examples/finnegans-wake-federated.py b/examples/finnegans-wake-federated.py new file mode 100644 index 000000000..654b54903 --- /dev/null +++ b/examples/finnegans-wake-federated.py @@ -0,0 +1,177 @@ +# This is an example of Alice setting a Policy on the NuCypher network. +# In this example, Alice uses n=3. + +# WIP w/ hendrix@3.1.0 + +import binascii +import datetime +import logging +import shutil +import sys +import os +import maya + +from nucypher.characters.lawful import Alice, Bob, Ursula +from nucypher.data_sources import DataSource +# This is already running in another process. +from nucypher.network.middleware import RestMiddleware +from umbral.keys import UmbralPublicKey + +## +# Boring setup stuff. +## + +root = logging.getLogger() +root.setLevel(logging.DEBUG) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(logging.INFO) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +ch.setFormatter(formatter) +root.addHandler(ch) + +teacher_rest_port = sys.argv[2] +with open("examples-runtime-cruft/node-metadata-{}".format(teacher_rest_port), "r") as f: + f.seek(0) + teacher_bytes = binascii.unhexlify(f.read()) +URSULA = Ursula.from_bytes(teacher_bytes, federated_only=True) +print("Will learn from {}".format(URSULA)) + +SHARED_CRUFTSPACE = "{}/examples-runtime-cruft".format(os.path.dirname(os.path.abspath(__file__))) +CRUFTSPACE = "{}/finnegans-wake-demo".format(SHARED_CRUFTSPACE) +CERTIFICATE_DIR = "{}/certs".format(CRUFTSPACE) +shutil.rmtree(CRUFTSPACE, ignore_errors=True) +os.mkdir(CRUFTSPACE) +os.mkdir(CERTIFICATE_DIR) + +URSULA.save_certificate_to_disk(CERTIFICATE_DIR) + +######### +# Alice # +######### + + +ALICE = Alice(network_middleware=RestMiddleware(), + known_nodes=(URSULA,), + federated_only=True, + always_be_learning=True, + known_certificates_dir=CERTIFICATE_DIR, + ) # TODO: 289 + +# Here are our Policy details. +policy_end_datetime = maya.now() + datetime.timedelta(days=5) +m = 2 +n = 3 +label = b"secret/files/and/stuff" + +# Alice grants to Bob. +BOB = Bob(known_nodes=(URSULA,), + federated_only=True, + always_be_learning=True, + known_certificates_dir=CERTIFICATE_DIR) +ALICE.start_learning_loop(now=True) +policy = ALICE.grant(BOB, label, m=m, n=n, + expiration=policy_end_datetime) + +# Alice puts her public key somewhere for Bob to find later... +alices_pubkey_bytes_saved_for_posterity = bytes(ALICE.stamp) + +# ...and then disappears from the internet. +del ALICE +# (this is optional of course - she may wish to remain in order to create +# new policies in the future. The point is - she is no longer obligated. + +##################### +# some time passes. # +# ... # +# # +# ... # +# And now for Bob. # +##################### + +# Bob wants to join the policy so that he can receive any future +# data shared on it. +# He needs a few pieces of knowledge to do that. +BOB.join_policy(label, # The label - he needs to know what data he's after. + alices_pubkey_bytes_saved_for_posterity, # To verify the signature, he'll need Alice's public key. + # He can also bootstrap himself onto the network more quickly + # by providing a list of known nodes at this time. + node_list=[("localhost", 3601)] + ) + +# Now that Bob has joined the Policy, let's show how DataSources +# can share data with the members of this Policy and then how Bob retrieves it. +finnegans_wake = open(sys.argv[1], 'rb') + +# We'll also keep track of some metadata to gauge performance. +# You can safely ignore from here until... +################################################################################ + +start_time = datetime.datetime.now() + +for counter, plaintext in enumerate(finnegans_wake): + if counter % 20 == 0: + now_time = datetime.datetime.now() + time_delta = now_time - start_time + seconds = time_delta.total_seconds() + print("********************************") + print("Performed {} PREs".format(counter)) + print("Elapsed: {}".format(time_delta.total_seconds())) + print("PREs per second: {}".format(counter / seconds)) + print("********************************") + + ################################################################################ + # ...here. OK, pay attention again. + # Now it's time for... + + ##################### + # Using DataSources # + ##################### + + # Now Alice has set a Policy and Bob has joined it. + # You're ready to make some DataSources and encrypt for Bob. + + # It may also be helpful to imagine that you have multiple Bobs, + # multiple Labels, or both. + + # First we make a DataSource for this policy. + data_source = DataSource(policy_pubkey_enc=policy.public_key) + + # Here's how we generate a MessageKit for the Policy. We also get a signature + # here, which can be passed via a side-channel (or posted somewhere public as + # testimony) and verified if desired. In this case, the plaintext is a + # single passage from James Joyce's Finnegan's Wake. + # The matter of whether encryption makes the passage more or less readable + # is left to the reader to determine. + message_kit, _signature = data_source.encapsulate_single_message(plaintext) + + # The DataSource will want to be able to be verified by Bob, so it leaves + # its Public Key somewhere. + data_source_public_key = bytes(data_source.stamp) + + # It can save the MessageKit somewhere (IPFS, etc) and then it too can + # choose to disappear (although it may also opt to continue transmitting + # as many messages as may be appropriate). + del data_source + + ############### + # Back to Bob # + ############### + + # Bob needs to reconstruct the DataSource. + datasource_as_understood_by_bob = DataSource.from_public_keys( + policy_public_key=policy.public_key, + datasource_public_key=data_source_public_key, + label=label + ) + + # Now Bob can retrieve the original message. He just needs the MessageKit + # and the DataSource which produced it. + alice_pubkey_restored_from_ancient_scroll = UmbralPublicKey.from_bytes(alices_pubkey_bytes_saved_for_posterity) + delivered_cleartexts = BOB.retrieve(message_kit=message_kit, + data_source=datasource_as_understood_by_bob, + alice_verifying_key=alice_pubkey_restored_from_ancient_scroll) + + # We show that indeed this is the passage originally encrypted by the DataSource. + assert plaintext == delivered_cleartexts[0] + print("Retrieved: {}".format(delivered_cleartexts[0])) diff --git a/examples/run_federated_ursula.py b/examples/run_federated_ursula.py new file mode 100644 index 000000000..776e63445 --- /dev/null +++ b/examples/run_federated_ursula.py @@ -0,0 +1,81 @@ +# This is not an actual mining script. Don't use this to mine - you won't +# perform any re-encryptions, and you won't get paid. +# It might be (but might not be) useful for determining whether you have +# the proper depedencies and configuration to run an actual mining node. + +# WIP w/ hendrix@tags/3.3.0rc1 + +import asyncio +import binascii +import logging +import os +import shutil +import sys + +from nucypher.characters.lawful import Ursula + +root = logging.getLogger() +root.setLevel(logging.DEBUG) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(logging.INFO) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +ch.setFormatter(formatter) +root.addHandler(ch) + +MY_REST_PORT = sys.argv[1] +# TODO: Use real path tooling here. +SHARED_CRUFTSPACE = "{}/examples-runtime-cruft".format(os.path.dirname(os.path.abspath(__file__))) +CRUFTSPACE = "{}/{}".format(SHARED_CRUFTSPACE, MY_REST_PORT) +DB_NAME = "{}/database".format(CRUFTSPACE) +CERTIFICATE_DIR = "{}/certs".format(CRUFTSPACE) + + +def spin_up_ursula(rest_port, db_name, teachers=(), certificate_dir=None): + metadata_file = "examples-runtime-cruft/node-metadata-{}".format(rest_port) + + asyncio.set_event_loop(asyncio.new_event_loop()) # Ugh. Awful. But needed until we shed the DHT. + _URSULA = Ursula(rest_port=rest_port, + rest_host="localhost", + db_name=db_name, + federated_only=True, + known_nodes=teachers, + known_certificates_dir=certificate_dir + ) + try: + with open(metadata_file, "w") as f: + f.write(bytes(_URSULA).hex()) + _URSULA.start_learning_loop() + _URSULA.get_deployer().run() + finally: + os.remove(db_name) + os.remove(metadata_file) + + +if __name__ == "__main__": + try: + shutil.rmtree(CRUFTSPACE, ignore_errors=True) + os.mkdir(CRUFTSPACE) + os.mkdir(CERTIFICATE_DIR) + try: + teacher_rest_port = sys.argv[2] + # TODO: Implement real path tooling here. + with open("{}/node-metadata-{}".format(SHARED_CRUFTSPACE, + teacher_rest_port), "r") as f: + f.seek(0) + teacher_bytes = binascii.unhexlify(f.read()) + teacher = Ursula.from_bytes(teacher_bytes, + federated_only=True) + teacher.save_certificate_to_disk(directory=CERTIFICATE_DIR) + teachers = (teacher,) + print("Will learn from {}".format(teacher)) + except IndexError: + teachers = () + except FileNotFoundError as e: + raise ValueError("Can't find a metadata file for node {}".format(teacher_rest_port)) + + spin_up_ursula(MY_REST_PORT, DB_NAME, + teachers=teachers, + certificate_dir=CERTIFICATE_DIR) + finally: + shutil.rmtree(CRUFTSPACE)