mirror of https://github.com/nucypher/nucypher.git
Comments and code reorganization
parent
405560ba34
commit
48dc1b9e08
|
@ -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(),
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue