Comments and code reorganization

pull/618/head
David Núñez 2018-11-27 13:47:21 +01:00 committed by Kieran Prasch
parent 405560ba34
commit 48dc1b9e08
3 changed files with 94 additions and 78 deletions

View File

@ -4,20 +4,17 @@ from nucypher.config.storages import LocalFileBasedNodeStorage
from nucypher.crypto.powers import EncryptingPower, SigningPower
from nucypher.network.middleware import RestMiddleware
from nucypher.utilities.logging import simpleObserver
from umbral.keys import UmbralPublicKey
from doctor_keys import get_doctor_pubkeys
import datetime
import os
import shutil
import maya
import json
import sys
from twisted.logger import globalLogPublisher
POLICY_FILENAME = "policy.json"
POLICY_FILENAME = "policy-metadata.json"
######################
# Boring setup stuff #
@ -30,29 +27,22 @@ globalLogPublisher.addObserver(simpleObserver)
TEMP_ALICE_DIR = "{}/alicia-files".format(os.path.dirname(os.path.abspath(__file__)))
TEMP_URSULA_CERTIFICATE_DIR = "{}/ursula-certs".format(TEMP_ALICE_DIR)
SEEDNODE_URL = "SEEDNODE URL ..."
# We expect the url of the seednode as the first argument.
SEEDNODE_URL = sys.argv[1]
# Here are our Policy details.
policy_end_datetime = maya.now() + datetime.timedelta(days=5)
m, n = 3, 5
label = b"label-"+os.urandom(4).hex().encode()
######################################
# Alice, the Authority of the Policy #
######################################
#######################################
# Alicia, the Authority of the Policy #
#######################################
# We get a persistent Alice.
passphrase = "TEST_ALICIA_INSECURE_DEVELOPMENT_PASSWORD"
try: # If we had an existing Alicia in disk, let's get it from there
alice_config_file = os.path.join(TEMP_ALICE_DIR, "config_root", "alice.config")
new_alice_config = AliceConfiguration.from_configuration_file(
filepath=alice_config_file,
network_middleware=RestMiddleware(),
#known_nodes={ursula},
start_learning_now=False,
save_metadata=False,
)
@ -68,7 +58,6 @@ except: # If anything fails, let's create Alicia from scratch
federated_only=True,
minimum_stake=0)
# Let's create an Alice from a Configuration.
# This requires creating a local storage for her first.
node_storage = LocalFileBasedNodeStorage(
@ -87,49 +76,76 @@ except: # If anything fails, let's create Alicia from scratch
known_nodes={ursula},
start_learning_now=False,
federated_only=True,
#save_metadata=False,
#load_metadata=False,
learn_on_same_thread=True,
)
alicia = alice_config(passphrase=passphrase,
known_certificates_dir=TEMP_URSULA_CERTIFICATE_DIR,
)
# We will save Alice's config to a file for later use
# We will save Alicia's config to a file for later use
alice_config_file = alice_config.to_configuration_file()
#print(alice_config_file)
# Let's get to learn about the NuCypher network
alicia.start_learning_loop(now=True)
# Alicia can create the public key associated to the label,
# even before creating any policy.
# At this point, Alicia is fully operational and can create policies.
# The Policy Label is a bytestring that categorizes the data that Alicia wants to share.
# Note: we add some random chars to create different policies, only for demonstration purposes
label = "heart-data-❤️-"+os.urandom(4).hex()
label = label.encode()
# Alicia can create the public key associated to the policy label,
# even before creating any associated policy.
policy_pubkey = alicia.get_policy_pubkey_from_label(label)
# This illustrates that Data Sources can produce encrypted data for policies
print("The policy public key for "
"label '{}' is {}".format(label.decode("utf-8"), policy_pubkey.to_bytes().hex()))
# Data Sources can produce encrypted data for access policies
# that **don't exist yet**.
# In this example, we create a local file with encrypted data, containing
# heart rate measurements from a heart monitor
import heart_monitor
heart_monitor.generate_heart_rate_samples(policy_pubkey,
label=label,
save_as_file=True)
# Alicia now wants to share data associated with this label.
# To do so, she needs the public key of the recipient.
# In this example, we generate it on the fly (for demonstration purposes)
from doctor_keys import get_doctor_pubkeys
doctor_pubkeys = get_doctor_pubkeys()
print("doctor_pubkeys", doctor_pubkeys)
powers_and_material = {EncryptingPower: doctor_pubkeys['enc'],
SigningPower: doctor_pubkeys['sig']}
powers_and_material = {
EncryptingPower: doctor_pubkeys['enc'],
SigningPower: doctor_pubkeys['sig']
}
# We create a view of the Bob who's going to be granted access.
doctor_strange = Bob.from_public_keys(powers_and_material=powers_and_material,
federated_only=True)
alicia.start_learning_loop(now=True)
# Here are our remaining Policy details, such as:
# - Policy duration
policy_end_datetime = maya.now() + datetime.timedelta(days=5)
# - m-out-of-n: This means Alicia splits the re-encryption key in 5 pieces and
# she requires Bob to seek collaboration of at least 3 Ursulas
m, n = 3, 5
# With this information, Alicia creates a policy granting access to Bob.
# The policy is sent to the NuCypher network.
print("Creating access policy for the Doctor...")
policy = alicia.grant(bob=doctor_strange,
label=label,
m=m,
n=n,
expiration=policy_end_datetime)
print("Done!")
# For the demo, we need a way to share with Bob some additional info
# about the policy, so we store it in a JSON file
policy_info = {
"policy_pubkey": policy.public_key.to_bytes().hex(),
"alice_sig_pubkey": bytes(alicia.stamp).hex(),

View File

@ -1,11 +1,11 @@
import json
import os
import sys
import shutil
import pickle
import maya
import traceback
from timeit import default_timer as timer
from requests.exceptions import SSLError
from urllib.parse import urlparse
from nucypher.characters.lawful import Bob, Ursula
from nucypher.crypto.kits import UmbralMessageKit
@ -16,18 +16,12 @@ from nucypher.network.middleware import RestMiddleware
from umbral.keys import UmbralPublicKey
from doctor_keys import get_doctor_privkeys
import heart_monitor
######################
# Boring setup stuff #
######################
with open("policy.json", 'r') as f:
policy_data = json.load(f)
policy_pubkey = UmbralPublicKey.from_bytes(bytes.fromhex(policy_data["policy_pubkey"]))
alices_sig_pubkey = UmbralPublicKey.from_bytes(bytes.fromhex(policy_data["alice_sig_pubkey"]))
label = policy_data["label"].encode()
SEEDNODE_URL = "SEEDNODE URL ..."
SEEDNODE_URL = sys.argv[1]
# TODO: path joins?
TEMP_DOCTOR_DIR = "{}/doctor-files".format(os.path.dirname(os.path.abspath(__file__)))
@ -46,22 +40,19 @@ ursula = Ursula.from_seed_and_stake_info(host=SEEDNODE_URL,
federated_only=True,
minimum_stake=0)
print("Ursula: ", ursula)
# To create a Bob, we need the doctor's private keys previously generated.
from doctor_keys import get_doctor_privkeys
doctor_keys = get_doctor_privkeys()
bob_enc_keypair = EncryptingKeypair(private_key=doctor_keys["enc"])
bob_sig_keypair = SigningKeypair(private_key=doctor_keys["sig"])
enc_power = EncryptingPower(keypair=bob_enc_keypair)
sig_power = SigningPower(keypair=bob_sig_keypair)
power_ups = [enc_power, sig_power]
print("Creating Bob ...")
print("Creating the Doctor ...")
bob = Bob(
doctor = Bob(
is_me=True,
federated_only=True,
crypto_power_ups=power_ups,
@ -73,54 +64,63 @@ bob = Bob(
network_middleware=RestMiddleware(),
)
print("Bob = ", bob)
print("Doctor = ", doctor)
print("Bob joins policy for label ", label)
bob.join_policy(label, alices_sig_pubkey)
# Let's join the policy generated by Alicia. We just need some info about it.
with open("policy-metadata.json", 'r') as f:
policy_data = json.load(f)
policy_pubkey = UmbralPublicKey.from_bytes(bytes.fromhex(policy_data["policy_pubkey"]))
alices_sig_pubkey = UmbralPublicKey.from_bytes(bytes.fromhex(policy_data["alice_sig_pubkey"]))
label = policy_data["label"].encode()
# data = heart_monitor.generate_heart_rate_samples(policy_pubkey,
# label=label,
# save_as_file=False)
print("The Doctor joins policy for label '{}'".format(label.decode("utf-8")))
doctor.join_policy(label, alices_sig_pubkey)
data = pickle.load(open(heart_monitor.HEART_DATA_FILENAME, "rb"))
# Now that the Doctor joined the policy in the NuCypher network,
# he can retrieve encrypted data which he can decrypt with his private key.
# But first we need some encrypted data!
# Let's read the file produced by the heart monitor and unpack the MessageKits,
# which are the individual ciphertexts.
data = pickle.load(open("heart_data.pickle", "rb"))
message_kits = (UmbralMessageKit.from_bytes(k) for k in data['kits'])
# The doctor also needs to create a view of the Data Source from its public keys
data_source = DataSource.from_public_keys(
policy_public_key=policy_pubkey,
datasource_public_key=data['data_source'],
label=label
)
kits = (UmbralMessageKit.from_bytes(k) for k in data['kits'])
for message_kit in kits:
)
# Now he can ask the NuCypher network to get a re-encrypted version of each MessageKit.
for message_kit in message_kits:
try:
#print("Bob retrieves ...")
start = timer()
delivered_cleartexts = bob.retrieve(message_kit=message_kit,
data_source=data_source,
alice_verifying_key=alices_sig_pubkey
)
except SSLError as e:
node_ip = urlparse(e.request.url).hostname
print(">> Connection problem with node ", node_ip)
else:
retrieved_plaintexts = doctor.retrieve(
message_kit=message_kit,
data_source=data_source,
alice_verifying_key=alices_sig_pubkey
)
end = timer()
plaintext = pickle.loads(delivered_cleartexts[0])
plaintext = pickle.loads(retrieved_plaintexts[0])
# Now we can get the heart rate and the associated timestamp,
# generated by the heart rate monitor.
heart_rate = plaintext['heart_rate']
_timestamp = maya.MayaDT(plaintext['timestamp'])
timestamp = maya.MayaDT(plaintext['timestamp'])
# This code block simply pretty prints the heart rate info
terminal_size = shutil.get_terminal_size().columns
max_width = min(terminal_size, 120)
columns = max_width - 10 - 27
columns = max_width - 12 - 27
scale = columns/40
scaled_heart_rate = int(scale * (heart_rate - 60))
retrieval_time = "Retrieval time: {:8.2f} ms".format(1000*(end - start))
line = "* ({} BPM)".rjust(scaled_heart_rate, " ")
line = line.format(heart_rate)
line = ("-" * scaled_heart_rate) + "❤︎ ({} BPM)".format(heart_rate)
line = line.ljust(max_width - 27, " ") + retrieval_time
print(line)
except Exception as e:
# We just want to know what went wrong and continue the demo
traceback.print_exc()
print(line)

View File

@ -14,7 +14,7 @@ DEFAULT_LABEL = b"Alicia's heart data"
def generate_heart_rate_samples(policy_pubkey,
label: bytes = DEFAULT_LABEL,
samples: int = 30,
samples: int = 500,
save_as_file: bool = False):
data_source = DataSource(policy_pubkey_enc=policy_pubkey,
label=label)