mirror of https://github.com/nucypher/nucypher.git
Excavate reencryption logic onto Ursula proper.
parent
eba53f3206
commit
77b297ede3
|
@ -1252,21 +1252,42 @@ class Ursula(Teacher, Character, Worker):
|
|||
return constants.BYTESTRING_IS_URSULA_IFACE_INFO + bytes(self)
|
||||
|
||||
#
|
||||
# Utilities
|
||||
# Work Orders & Re-Encryption
|
||||
#
|
||||
|
||||
def work_orders(self, bob=None):
|
||||
"""
|
||||
TODO: This is better written as a model method for Ursula's datastore.
|
||||
"""
|
||||
if not bob:
|
||||
return self._work_orders
|
||||
else:
|
||||
work_orders_from_bob = []
|
||||
for work_order in self._work_orders:
|
||||
if work_order.bob == bob:
|
||||
work_orders_from_bob.append(work_order)
|
||||
return work_orders_from_bob
|
||||
def work_orders(self, bob=None) -> List['WorkOrder']:
|
||||
with ThreadedSession(self.datastore.engine):
|
||||
if not bob: # All
|
||||
return self.datastore.get_workorders()
|
||||
else: # Filter
|
||||
work_orders_from_bob = self.datastore.get_workorders(bob_verifying_key=bytes(bob.stamp))
|
||||
return work_orders_from_bob
|
||||
|
||||
def _reencrypt(self, kfrag: KFrag, work_order: 'WorkOrder', alice_verifying_key: UmbralPublicKey):
|
||||
|
||||
# Prepare a bytestring for concatenating re-encrypted
|
||||
# capsule data for each work order task.
|
||||
cfrag_byte_stream = bytes()
|
||||
for task in work_order.tasks:
|
||||
|
||||
# Ursula signs on top of Bob's signature of each task.
|
||||
# Now both are committed to the same task. See #259.
|
||||
reencryption_metadata = bytes(self.stamp(bytes(task.signature)))
|
||||
|
||||
# Ursula sets Alice's verifying key for capsule correctness verification.
|
||||
capsule = task.capsule
|
||||
capsule.set_correctness_keys(verifying=alice_verifying_key)
|
||||
|
||||
# Then re-encrypts the fragment.
|
||||
cfrag = pre.reencrypt(kfrag, capsule, metadata=reencryption_metadata) # <--- pyUmbral
|
||||
self.log.info(f"Re-encrypted capsule {capsule} -> made {cfrag}.")
|
||||
|
||||
# Next, Ursula signs to commit to her results.
|
||||
reencryption_signature = self.stamp(bytes(cfrag))
|
||||
cfrag_byte_stream += VariableLengthBytestring(cfrag) + reencryption_signature
|
||||
|
||||
# ... and finally returns all the re-encrypted bytes
|
||||
return cfrag_byte_stream
|
||||
|
||||
|
||||
class Enrico(Character):
|
||||
|
|
|
@ -124,7 +124,7 @@ def paint_node_status(emitter, ursula, start_time):
|
|||
'Rest Interface ...... {}'.format(ursula.rest_url()),
|
||||
'Node Storage Type ... {}'.format(ursula.node_storage._name.capitalize()),
|
||||
'Known Nodes ......... {}'.format(len(ursula.known_nodes)),
|
||||
'Work Orders ......... {}'.format(len(ursula._work_orders)),
|
||||
'Work Orders ......... {}'.format(len(ursula.work_orders())),
|
||||
teacher]
|
||||
|
||||
if not ursula.federated_only:
|
||||
|
|
|
@ -291,29 +291,37 @@ def make_rest_app(
|
|||
|
||||
@rest_app.route('/kFrag/<id_as_hex>/reencrypt', methods=["POST"])
|
||||
def reencrypt_via_rest(id_as_hex):
|
||||
from nucypher.policy.collections import WorkOrder # Avoid circular import
|
||||
arrangement_id = binascii.unhexlify(id_as_hex)
|
||||
|
||||
# Get Policy Arrangement
|
||||
try:
|
||||
arrangement_id = binascii.unhexlify(id_as_hex)
|
||||
except (binascii.Error, TypeError):
|
||||
return Response(response=b'Invalid arrangement ID', status=405)
|
||||
try:
|
||||
with ThreadedSession(db_engine) as session:
|
||||
arrangement = datastore.get_policy_arrangement(arrangement_id=id_as_hex.encode(), session=session)
|
||||
except NotFound:
|
||||
return Response(response=arrangement_id, status=404)
|
||||
kfrag_bytes = policy_arrangement.kfrag # Careful! :-)
|
||||
verifying_key_bytes = policy_arrangement.alice_verifying_key.key_data
|
||||
|
||||
# TODO: Push this to a lower level. Perhaps to Ursula character? #619
|
||||
kfrag = KFrag.from_bytes(kfrag_bytes)
|
||||
alices_verifying_key = UmbralPublicKey.from_bytes(verifying_key_bytes)
|
||||
alices_address = canonical_address_from_umbral_key(alices_verifying_key)
|
||||
# Get KFrag
|
||||
kfrag = KFrag.from_bytes(arrangement.kfrag) # Careful! :-)
|
||||
|
||||
# Get Work Order
|
||||
from nucypher.policy.collections import WorkOrder # Avoid circular import
|
||||
alice_verifying_key_bytes = arrangement.alice_verifying_key.key_data
|
||||
alice_verifying_key = UmbralPublicKey.from_bytes(alice_verifying_key_bytes)
|
||||
alice_address = canonical_address_from_umbral_key(alice_verifying_key)
|
||||
work_order_payload = request.data
|
||||
work_order = WorkOrder.from_rest_payload(arrangement_id=arrangement_id,
|
||||
rest_payload=request.data,
|
||||
rest_payload=work_order_payload,
|
||||
ursula=this_node,
|
||||
alice_address=alices_address)
|
||||
|
||||
alice_address=alice_address)
|
||||
log.info(f"Work Order from {work_order.bob}, signed {work_order.receipt_signature}")
|
||||
|
||||
cfrag_byte_stream = b""
|
||||
# Re-encrypt
|
||||
response = this_node._reencrypt(kfrag=kfrag,
|
||||
work_order=work_order,
|
||||
alice_verifying_key=alice_verifying_key)
|
||||
|
||||
# Now, Ursula saves this workorder to her database...
|
||||
with ThreadedSession(db_engine):
|
||||
|
|
|
@ -74,4 +74,4 @@ def test_workorder_sqlite_keystore(test_keystore):
|
|||
# Test del workorder
|
||||
deleted = test_keystore.del_workorders(arrangement_id)
|
||||
assert deleted > 0
|
||||
assert test_keystore.get_workorders(arrangement_id) == 0
|
||||
assert len(test_keystore.get_workorders(arrangement_id)) == 0
|
||||
|
|
Loading…
Reference in New Issue