def test_cfrag_serialization_no_proof_no_metadata(prepared_capsule, kfrags): for kfrag in kfrags: cfrag = pre.reencrypt(kfrag, prepared_capsule, provide_proof=False) cfrag_bytes = cfrag.to_bytes() proof = cfrag.proof assert proof is None assert len(cfrag_bytes) == CapsuleFrag.expected_bytes_length() new_cfrag = CapsuleFrag.from_bytes(cfrag_bytes) assert new_cfrag.point_e1 == cfrag.point_e1 assert new_cfrag.point_v1 == cfrag.point_v1 assert new_cfrag.kfrag_id == cfrag.kfrag_id assert new_cfrag.point_precursor == cfrag.point_precursor new_proof = new_cfrag.proof assert new_proof is None
def test_bob_can_issue_a_work_order_to_a_specific_ursula( enacted_federated_policy, federated_bob, federated_alice, federated_ursulas, capsule_side_channel): """ Now that Bob has his list of Ursulas, he can issue a WorkOrder to one. Upon receiving the WorkOrder, Ursula saves it and responds by re-encrypting and giving Bob a cFrag. This is a multipart test; it shows proper relations between the Characters Ursula and Bob and also proper interchange between a KFrag, Capsule, and CFrag object in the context of REST-driven proxy re-encryption. """ # We pick up our story with Bob already having followed the treasure map above, ie: hrac, treasure_map = enacted_federated_policy.hrac, enacted_federated_policy.treasure_map federated_bob.start_learning_loop() federated_bob.follow_treasure_map(treasure_map=treasure_map, block=True, timeout=1) assert len(federated_bob.known_nodes) == len(federated_ursulas) # Bob has no saved work orders yet, ever. assert len(federated_bob._completed_work_orders) == 0 # We'll test against just a single Ursula - here, we make a WorkOrder for just one. # We can pass any number of capsules as args; here we pass just one. capsule = capsule_side_channel().capsule capsule.set_correctness_keys( delegating=enacted_federated_policy.public_key, receiving=federated_bob.public_keys(DecryptingPower), verifying=federated_alice.stamp.as_umbral_pubkey()) work_orders, _ = federated_bob.work_orders_for_capsules( capsule, treasure_map=treasure_map, alice_verifying_key=federated_alice.stamp.as_umbral_pubkey(), num_ursulas=1) # Again: one Ursula, one work_order. assert len(work_orders) == 1 # Since we didn't tell Bob to cache the WorkOrders, Bob didn't save it. assert len(federated_bob._completed_work_orders) == 0 # This time, we'll tell Bob to cache it. retained_work_orders, _ = federated_bob.work_orders_for_capsules( capsule, treasure_map=treasure_map, alice_verifying_key=federated_alice.stamp.as_umbral_pubkey(), num_ursulas=1) # The work order we just made is not yet complete, of course. address, work_order = list(retained_work_orders.items())[0] assert work_order.completed is False # **** RE-ENCRYPTION HAPPENS HERE! **** _success, cfrags = federated_bob._reencrypt(work_order, retain_cfrags=True) # We only gave one Capsule, so we only got one cFrag. assert len(cfrags) == 1 the_cfrag = cfrags[0] # ...and the work order is complete. assert work_order.completed # Attach the CFrag to the Capsule. capsule.attach_cfrag(the_cfrag) # Having received the cFrag, Bob also saved the WorkOrder as complete. assert len(federated_bob._completed_work_orders.by_ursula[address]) == 1 # OK, so cool - Bob has his cFrag! Let's make sure everything went properly. First, we'll show that it is in fact # the correct cFrag (ie, that Ursula performed re-encryption properly). for u in federated_ursulas: if u.rest_interface.port == work_order.ursula.rest_interface.port: ursula = u break else: raise RuntimeError( "We've lost track of the Ursula that has the WorkOrder. Can't really proceed." ) with ursula.datastore.describe( PolicyArrangement, work_order.arrangement_id.hex()) as policy_arrangement: the_kfrag = policy_arrangement.kfrag the_correct_cfrag = pre.reencrypt(the_kfrag, capsule) # The first CFRAG_LENGTH_WITHOUT_PROOF bytes (ie, the cfrag proper, not the proof material), are the same: assert bytes(the_cfrag)[:CapsuleFrag.expected_bytes_length()] == bytes( the_correct_cfrag)[:CapsuleFrag.expected_bytes_length( )] # It's the correct cfrag! assert the_correct_cfrag.verify_correctness(capsule) # Now we'll show that Ursula saved the correct WorkOrder. with ursula.datastore.query_by( Workorder, filter_field='bob_verifying_key', filter_func=lambda bob_key: bob_key == federated_bob.stamp. as_umbral_pubkey()) as work_orders_from_bob: assert len(work_orders_from_bob) == 1 assert work_orders_from_bob[ 0].bob_signature == work_order.receipt_signature
def test_bob_can_issue_a_work_order_to_a_specific_ursula(enacted_federated_policy, federated_bob, federated_alice, federated_ursulas, capsule_side_channel): """ Now that Bob has his list of Ursulas, he can issue a WorkOrder to one. Upon receiving the WorkOrder, Ursula saves it and responds by re-encrypting and giving Bob a cFrag. This is a multipart test; it shows proper relations between the Characters Ursula and Bob and also proper interchange between a KFrag, Capsule, and CFrag object in the context of REST-driven proxy re-encryption. """ # We pick up our story with Bob already having followed the treasure map above, ie: hrac, treasure_map = enacted_federated_policy.hrac(), enacted_federated_policy.treasure_map map_id = treasure_map.public_id() federated_bob.treasure_maps[map_id] = treasure_map federated_bob.start_learning_loop() federated_bob.follow_treasure_map(map_id=map_id, block=True, timeout=1) assert len(federated_bob.known_nodes) == len(federated_ursulas) # Bob has no saved work orders yet, ever. assert len(federated_bob._saved_work_orders) == 0 # We'll test against just a single Ursula - here, we make a WorkOrder for just one. # We can pass any number of capsules as args; here we pass just one. capsule = capsule_side_channel[0].capsule capsule.set_correctness_keys(delegating=enacted_federated_policy.public_key, receiving=federated_bob.public_keys(DecryptingPower), verifying=federated_alice.stamp.as_umbral_pubkey()) work_orders = federated_bob.generate_work_orders(map_id, capsule, num_ursulas=1) # Again: one Ursula, one work_order. assert len(work_orders) == 1 # Bob saved the WorkOrder. assert len(federated_bob._saved_work_orders) == 1 # And the Ursula. assert len(federated_bob._saved_work_orders.ursulas) == 1 ursula_id, work_order = list(work_orders.items())[0] # The work order is not yet complete, of course. assert work_order.completed is False # **** RE-ENCRYPTION HAPPENS HERE! **** cfrags = federated_bob.get_reencrypted_cfrags(work_order) # We only gave one Capsule, so we only got one cFrag. assert len(cfrags) == 1 the_cfrag = cfrags[0] # ...and the work order is complete. assert work_order.completed # Attach the CFrag to the Capsule. capsule.attach_cfrag(the_cfrag) # Having received the cFrag, Bob also saved the WorkOrder as complete. assert len(federated_bob._saved_work_orders.by_ursula[ursula_id]) == 1 # OK, so cool - Bob has his cFrag! Let's make sure everything went properly. First, we'll show that it is in fact # the correct cFrag (ie, that Ursula performed re-encryption properly). for u in federated_ursulas: if u.rest_information()[0].port == work_order.ursula.rest_information()[0].port: ursula = u break else: raise RuntimeError("We've lost track of the Ursula that has the WorkOrder. Can't really proceed.") kfrag_bytes = ursula.datastore.get_policy_arrangement( work_order.arrangement_id.hex().encode()).kfrag the_kfrag = KFrag.from_bytes(kfrag_bytes) the_correct_cfrag = pre.reencrypt(the_kfrag, capsule) # The first CFRAG_LENGTH_WITHOUT_PROOF bytes (ie, the cfrag proper, not the proof material), are the same: assert bytes(the_cfrag)[:CapsuleFrag.expected_bytes_length()] == bytes( the_correct_cfrag)[:CapsuleFrag.expected_bytes_length()] # It's the correct cfrag! assert the_correct_cfrag.verify_correctness(capsule) # Now we'll show that Ursula saved the correct WorkOrder. work_orders_from_bob = ursula.work_orders(bob=federated_bob) assert len(work_orders_from_bob) == 1 assert work_orders_from_bob[0] == work_order