Extract kfrag authorization into a class

pull/2745/head
Bogdan Opanchuk 2021-07-09 22:45:25 -07:00
parent e5c0bb079e
commit 8c628da9ea
7 changed files with 114 additions and 65 deletions

View File

@ -108,7 +108,7 @@ from nucypher.network.nodes import NodeSprout, TEACHER_NODES, Teacher
from nucypher.network.protocols import InterfaceInfo, parse_node_uri from nucypher.network.protocols import InterfaceInfo, parse_node_uri
from nucypher.network.server import ProxyRESTServer, TLSHostingPower, make_rest_app from nucypher.network.server import ProxyRESTServer, TLSHostingPower, make_rest_app
from nucypher.network.trackers import AvailabilityTracker from nucypher.network.trackers import AvailabilityTracker
from nucypher.policy.maps import TreasureMap from nucypher.policy.maps import TreasureMap, AuthorizedKeyFrag
from nucypher.policy.orders import WorkOrder from nucypher.policy.orders import WorkOrder
from nucypher.policy.policies import Policy from nucypher.policy.policies import Policy
from nucypher.utilities.logging import Logger from nucypher.utilities.logging import Logger
@ -1737,35 +1737,29 @@ class Ursula(Teacher, Character, Worker):
# #
def verify_kfrag_authorization(self, def verify_kfrag_authorization(self,
alice: Alice, hrac: bytes,
kfrag: KeyFrag, author: Alice,
signed_writ: bytes, publisher: Alice,
work_order: 'WorkOrder' authorized_kfrag: AuthorizedKeyFrag,
) -> VerifiedKeyFrag: ) -> VerifiedKeyFrag:
from nucypher.policy.orders import WorkOrder # TODO: resolve ciruclar dependency
writ_hrac, writ_kfrag_checksum, writ_signature = WorkOrder.signed_writ_splitter(signed_writ) # TODO: should it be a method of AuthorizedKeyFrag?
reconstructed_writ = writ_hrac + writ_kfrag_checksum
try: try:
self.verify_from(alice, reconstructed_writ, signature=writ_signature) self.verify_from(publisher, authorized_kfrag.writ, signature=authorized_kfrag.writ_signature)
except InvalidSignature: except InvalidSignature:
# TODO (#2740): differentiate cases for Policy.Unauthorized # TODO (#2740): differentiate cases for Policy.Unauthorized
raise Policy.Unauthorized # This isn't from Alice (publisher). raise Policy.Unauthorized # This isn't from Alice (publisher).
if writ_hrac != work_order.hrac: # Funky Workorder if authorized_kfrag.hrac != hrac: # Funky Workorder
raise Policy.Unauthorized # Bob, what the *hell* are you doing? raise Policy.Unauthorized # Bob, what the *hell* are you doing?
kfrag_checksum = keccak_digest(bytes(kfrag))[:WRIT_CHECKSUM_SIZE]
if kfrag_checksum != writ_kfrag_checksum:
raise Policy.Unauthorized # Bob, Seriously?
try: try:
verified_kfrag = kfrag.verify(verifying_pk=alice.stamp.as_umbral_pubkey()) verified_kfrag = authorized_kfrag.kfrag.verify(verifying_pk=author.stamp.as_umbral_pubkey())
except VerificationError: except VerificationError:
raise Policy.Unauthorized # WTF, Alice did not generate these KFrags. raise Policy.Unauthorized # WTF, Alice did not generate these KFrags.
if writ_hrac in self.revoked_policies: if authorized_kfrag.hrac in self.revoked_policies:
# Note: This is only an off-chain and in-memory check. # Note: This is only an off-chain and in-memory check.
raise Policy.Unauthorized # Denied raise Policy.Unauthorized # Denied

View File

@ -24,7 +24,10 @@ SIGNATURE_SIZE = 64
EIP712_MESSAGE_SIGNATURE_SIZE = 65 EIP712_MESSAGE_SIGNATURE_SIZE = 65
WRIT_CHECKSUM_SIZE = 32 WRIT_CHECKSUM_SIZE = 32
SIGNED_WRIT_SIZE = HRAC_LENGTH + WRIT_CHECKSUM_SIZE + SIGNATURE_SIZE SIGNED_WRIT_SIZE = HRAC_LENGTH + WRIT_CHECKSUM_SIZE + SIGNATURE_SIZE
ENCRYPTED_KFRAG_PAYLOAD_LENGTH = 619 # Depends on encryption parameters in Umbral, has to be hardcoded
# The size of a serialized message kit encrypting an AuthorizedKeyFrag.
# Depends on encryption parameters in Umbral, has to be hardcoded.
ENCRYPTED_KFRAG_PAYLOAD_LENGTH = 619
# Digest Lengths # Digest Lengths
KECCAK_DIGEST_LENGTH = 32 KECCAK_DIGEST_LENGTH = 32

View File

@ -220,14 +220,21 @@ def _make_rest_app(datastore: Datastore, this_node, domain: str, log: Logger) ->
return Response(response="KFrag decryption failed.", status=403) # 403 - Forbidden return Response(response="KFrag decryption failed.", status=403) # 403 - Forbidden
# Verify KFrag Authorization (offchain) # Verify KFrag Authorization (offchain)
signed_writ, kfrag = work_order.kfrag_payload_splitter(plaintext_kfrag_payload) from nucypher.policy.maps import AuthorizedKeyFrag
try: try:
verified_kfrag = this_node.verify_kfrag_authorization( authorized_kfrag = AuthorizedKeyFrag.from_bytes(plaintext_kfrag_payload)
alice=policy_publisher, except ValueError:
kfrag=kfrag, message = f'{bob_identity_message} Invalid AuthorizedKeyFrag.'
signed_writ=signed_writ, log.info(message)
work_order=work_order this_node.suspicious_activities_witnessed['unauthorized'].append(message)
) return Response(message, status=401) # 401 - Unauthorized
try:
verified_kfrag = this_node.verify_kfrag_authorization(hrac=work_order.hrac,
author=alice,
publisher=policy_publisher,
authorized_kfrag=authorized_kfrag)
except Policy.Unauthorized: except Policy.Unauthorized:
message = f'{bob_identity_message} Unauthorized work order.' message = f'{bob_identity_message} Unauthorized work order.'
log.info(message) log.info(message)

View File

@ -35,12 +35,68 @@ from nucypher.crypto.constants import HRAC_LENGTH, WRIT_CHECKSUM_SIZE, EIP712_ME
from nucypher.crypto.kits import UmbralMessageKit from nucypher.crypto.kits import UmbralMessageKit
from nucypher.crypto.powers import DecryptingPower, SigningPower from nucypher.crypto.powers import DecryptingPower, SigningPower
from nucypher.crypto.signing import SignatureStamp from nucypher.crypto.signing import SignatureStamp
from nucypher.crypto.splitters import signature_splitter from nucypher.crypto.splitters import signature_splitter, hrac_splitter, kfrag_splitter
from nucypher.crypto.umbral_adapter import KeyFrag, PublicKey, Signature from nucypher.crypto.umbral_adapter import KeyFrag, VerifiedKeyFrag, PublicKey, Signature
from nucypher.crypto.utils import keccak_digest, encrypt_and_sign, verify_eip_191 from nucypher.crypto.utils import keccak_digest, encrypt_and_sign, verify_eip_191
from nucypher.network.middleware import RestMiddleware from nucypher.network.middleware import RestMiddleware
class AuthorizedKeyFrag:
_splitter = BytestringSplitter(
hrac_splitter, # HRAC
BytestringSplitter((bytes, WRIT_CHECKSUM_SIZE)), # kfrag checksum
signature_splitter, # Publisher's signature
kfrag_splitter,
)
@staticmethod
def _kfrag_checksum(kfrag: KeyFrag) -> bytes:
return keccak_digest(bytes(kfrag))[:WRIT_CHECKSUM_SIZE]
@classmethod
def construct_by_publisher(cls,
hrac: bytes,
verified_kfrag: VerifiedKeyFrag,
publisher_stamp: SignatureStamp,
) -> 'AuthorizedKeyFrag':
# "un-verify" kfrag to keep further logic streamlined
kfrag = KeyFrag.from_bytes(bytes(verified_kfrag))
# Alice makes plain to Ursula that, upon decrypting this message,
# this particular KFrag is authorized for use in the policy identified by this HRAC.
kfrag_checksum = cls._kfrag_checksum(kfrag)
writ = hrac + kfrag_checksum
writ_signature = publisher_stamp(writ)
# The writ and the KFrag together represent a complete kfrag kit: the entirety of
# the material needed for Ursula to assuredly service this policy.
return cls(hrac, kfrag_checksum, writ_signature, kfrag)
def __init__(self, hrac: bytes, kfrag_checksum: bytes, writ_signature: Signature, kfrag: KeyFrag):
self.hrac = hrac
self.kfrag_checksum = kfrag_checksum
self.writ = hrac + kfrag_checksum
self.writ_signature = writ_signature
self.kfrag = kfrag
def __bytes__(self):
return self.writ + bytes(self.writ_signature) + bytes(self.kfrag)
@classmethod
def from_bytes(cls, data: bytes):
# TODO: should we check the signature right away here?
hrac, kfrag_checksum, writ_signature, kfrag = cls._splitter(data)
# Check integrity
calculated_checksum = cls._kfrag_checksum(kfrag)
if calculated_checksum != kfrag_checksum:
raise ValueError("Incorrect KeyFrag checksum in the serialized data")
return cls(hrac, kfrag_checksum, writ_signature, kfrag)
class TreasureMapSplitter(BrandingMixin, VersioningMixin, BytestringKwargifier): class TreasureMapSplitter(BrandingMixin, VersioningMixin, BytestringKwargifier):
pass pass
@ -214,24 +270,7 @@ class TreasureMap:
nodes_as_bytes += (node_id + kfrag) nodes_as_bytes += (node_id + kfrag)
return nodes_as_bytes return nodes_as_bytes
def _make_writ(self, kfrag, publisher_stamp) -> bytes: def add_kfrag(self, ursula, verified_kfrag: VerifiedKeyFrag, publisher_stamp: SignatureStamp) -> None:
"""
Alice makes plain to Ursula that, upon decrypting this message,
this particular KFrag is authorized for use in the policy identified by this HRAC.
"""
writ = self._hrac + keccak_digest(bytes(kfrag))[:WRIT_CHECKSUM_SIZE]
writ_signature = bytes(publisher_stamp(writ))
signed_writ = writ + writ_signature
return signed_writ
def _make_kfrag_payload(self, kfrag, publisher_stamp) -> bytes:
# The writ and the KFrag together represent a complete kfrag kit: the entirety of
# the material needed for Ursula to assuredly service this policy.
signed_writ = self._make_writ(kfrag=kfrag, publisher_stamp=publisher_stamp)
kfrag_payload = signed_writ + bytes(kfrag)
return kfrag_payload
def add_kfrag(self, ursula, kfrag, publisher_stamp: SignatureStamp) -> None:
if self.destinations == NO_DECRYPTION_PERFORMED: if self.destinations == NO_DECRYPTION_PERFORMED:
# Unsure how this situation can arise, but let's raise an error just in case. # Unsure how this situation can arise, but let's raise an error just in case.
raise TypeError("This TreasureMap is encrypted. You can't add another node without decrypting it.") raise TypeError("This TreasureMap is encrypted. You can't add another node without decrypting it.")
@ -242,7 +281,9 @@ class TreasureMap:
'Cannot add KFrag to TreasureMap without an HRAC set. Call "derive_hrac" and try again.') 'Cannot add KFrag to TreasureMap without an HRAC set. Call "derive_hrac" and try again.')
# Encrypt this kfrag payload for Ursula. # Encrypt this kfrag payload for Ursula.
kfrag_payload = self._make_kfrag_payload(kfrag=kfrag, publisher_stamp=publisher_stamp) kfrag_payload = bytes(AuthorizedKeyFrag.construct_by_publisher(hrac=self._hrac,
verified_kfrag=verified_kfrag,
publisher_stamp=publisher_stamp))
encrypted_kfrag, _signature = encrypt_and_sign(recipient_pubkey_enc=ursula.public_keys(DecryptingPower), encrypted_kfrag, _signature = encrypt_and_sign(recipient_pubkey_enc=ursula.public_keys(DecryptingPower),
plaintext=kfrag_payload, plaintext=kfrag_payload,
signer=publisher_stamp) signer=publisher_stamp)
@ -295,7 +336,7 @@ class TreasureMap:
bob: 'Bob', bob: 'Bob',
label: bytes, label: bytes,
ursulas: Sequence['Ursula'], ursulas: Sequence['Ursula'],
kfrags: Sequence[KeyFrag], verified_kfrags: Sequence[VerifiedKeyFrag],
m: int m: int
) -> 'TreasureMap': ) -> 'TreasureMap':
"""Create a new treasure map for a collection of ursulas and kfrags.""" """Create a new treasure map for a collection of ursulas and kfrags."""
@ -307,9 +348,9 @@ class TreasureMap:
label=label) label=label)
# Encrypt each kfrag for an Ursula. # Encrypt each kfrag for an Ursula.
for ursula, kfrag in zip(ursulas, kfrags): for ursula, verified_kfrag in zip(ursulas, verified_kfrags):
treasure_map.add_kfrag(ursula=ursula, treasure_map.add_kfrag(ursula=ursula,
kfrag=kfrag, verified_kfrag=verified_kfrag,
publisher_stamp=publisher.stamp) publisher_stamp=publisher.stamp)
# Sign the map if needed before sending it out into the world. # Sign the map if needed before sending it out into the world.

View File

@ -31,7 +31,7 @@ from nucypher.crypto.kits import RevocationKit
from nucypher.crypto.powers import TransactingPower from nucypher.crypto.powers import TransactingPower
from nucypher.crypto.splitters import key_splitter from nucypher.crypto.splitters import key_splitter
from nucypher.crypto.utils import keccak_digest from nucypher.crypto.utils import keccak_digest
from nucypher.crypto.umbral_adapter import PublicKey, KeyFrag, Signature from nucypher.crypto.umbral_adapter import PublicKey, VerifiedKeyFrag, Signature
from nucypher.crypto.utils import construct_policy_id from nucypher.crypto.utils import construct_policy_id
from nucypher.network.middleware import RestMiddleware from nucypher.network.middleware import RestMiddleware
from nucypher.policy.reservoir import ( from nucypher.policy.reservoir import (
@ -196,7 +196,7 @@ class Policy(ABC):
label: bytes, label: bytes,
expiration: maya.MayaDT, expiration: maya.MayaDT,
bob: 'Bob', bob: 'Bob',
kfrags: Sequence[KeyFrag], kfrags: Sequence[VerifiedKeyFrag],
public_key: PublicKey, public_key: PublicKey,
m: int, m: int,
): ):
@ -351,7 +351,7 @@ class Policy(ABC):
bob=self.bob, bob=self.bob,
label=self.label, label=self.label,
ursulas=list(arrangements), ursulas=list(arrangements),
kfrags=self.kfrags, verified_kfrags=self.kfrags,
m=self.m) m=self.m)
return treasure_map return treasure_map
@ -418,7 +418,7 @@ class Policy(ABC):
raise NotImplementedError raise NotImplementedError
@abstractmethod @abstractmethod
def _make_enactment_payload(self, kfrag: KeyFrag) -> bytes: def _make_enactment_payload(self, kfrag: VerifiedKeyFrag) -> bytes:
""" """
Serializes a given kfrag and policy publication transaction to send to Ursula. Serializes a given kfrag and policy publication transaction to send to Ursula.
""" """

View File

@ -26,6 +26,7 @@ from nucypher.crypto.kits import PolicyMessageKit
from nucypher.crypto.powers import DecryptingPower from nucypher.crypto.powers import DecryptingPower
from nucypher.crypto.umbral_adapter import reencrypt from nucypher.crypto.umbral_adapter import reencrypt
from nucypher.datastore.models import Workorder from nucypher.datastore.models import Workorder
from nucypher.policy.maps import AuthorizedKeyFrag
from tests.utils.middleware import MockRestMiddleware, NodeIsDownMiddleware from tests.utils.middleware import MockRestMiddleware, NodeIsDownMiddleware
@ -206,13 +207,16 @@ def test_bob_can_issue_a_work_order_to_a_specific_ursula(enacted_federated_polic
# Ursula decrypts the encrypted KFrag # Ursula decrypts the encrypted KFrag
encrypted_kfrag = enacted_federated_policy.treasure_map.destinations[ursula.checksum_address] encrypted_kfrag = enacted_federated_policy.treasure_map.destinations[ursula.checksum_address]
alice = Alice.from_public_keys(verifying_key=enacted_federated_policy.publisher_verifying_key) alice = Alice.from_public_keys(verifying_key=federated_alice.stamp.as_umbral_pubkey())
plaintext_kfrag_payload = ursula.verify_from(stranger=alice, plaintext_kfrag_payload = ursula.verify_from(stranger=alice,
message_kit=encrypted_kfrag, message_kit=encrypted_kfrag,
decrypt=True) decrypt=True)
_signed_writ, the_kfrag = work_order.kfrag_payload_splitter(plaintext_kfrag_payload) authorized_kfrag = AuthorizedKeyFrag.from_bytes(plaintext_kfrag_payload)
verified_kfrag = ursula.verify_kfrag_authorization(hrac=work_order.hrac,
author=alice,
publisher=alice,
authorized_kfrag=authorized_kfrag)
verified_kfrag = the_kfrag.verify(enacted_federated_policy.publisher_verifying_key)
reencrypt(capsule=message_kit.capsule, kfrag=verified_kfrag) reencrypt(capsule=message_kit.capsule, kfrag=verified_kfrag)
# Now we'll show that Ursula saved the correct WorkOrder. # Now we'll show that Ursula saved the correct WorkOrder.

View File

@ -22,18 +22,18 @@ import pytest
from nucypher.crypto.powers import DecryptingPower, SigningPower from nucypher.crypto.powers import DecryptingPower, SigningPower
from nucypher.crypto.umbral_adapter import KeyFrag from nucypher.crypto.umbral_adapter import KeyFrag
from nucypher.policy.maps import TreasureMap from nucypher.policy.maps import TreasureMap, AuthorizedKeyFrag
def test_complete_treasure_map_journey(federated_alice, federated_bob, federated_ursulas, mocker): def test_complete_treasure_map_journey(federated_alice, federated_bob, federated_ursulas, idle_federated_policy, mocker):
treasure_map = TreasureMap(m=1) treasure_map = TreasureMap(m=1)
bob_encrypting_key = federated_bob.public_keys(DecryptingPower) bob_encrypting_key = federated_bob.public_keys(DecryptingPower)
bob_verifying_key = federated_bob.public_keys(SigningPower) bob_verifying_key = federated_bob.public_keys(SigningPower)
mock_kfrag = os.urandom(KeyFrag.serialized_size()) kfrag = idle_federated_policy.kfrags[0]
make_kfrag_payload_spy = mocker.spy(TreasureMap, '_make_kfrag_payload') make_kfrag_payload_spy = mocker.spy(AuthorizedKeyFrag, '__bytes__')
treasure_map.derive_hrac(publisher_stamp=federated_alice.stamp, treasure_map.derive_hrac(publisher_stamp=federated_alice.stamp,
bob_verifying_key=bob_verifying_key, bob_verifying_key=bob_verifying_key,
@ -41,7 +41,7 @@ def test_complete_treasure_map_journey(federated_alice, federated_bob, federated
encrypted_kfrags = dict() encrypted_kfrags = dict()
for ursula in federated_ursulas: for ursula in federated_ursulas:
treasure_map.add_kfrag(ursula, mock_kfrag, federated_alice.stamp) treasure_map.add_kfrag(ursula, kfrag, federated_alice.stamp)
encrypted_kfrags[ursula.checksum_address] = make_kfrag_payload_spy.spy_return encrypted_kfrags[ursula.checksum_address] = make_kfrag_payload_spy.spy_return
treasure_map.prepare_for_publication(bob_encrypting_key=bob_encrypting_key, treasure_map.prepare_for_publication(bob_encrypting_key=bob_encrypting_key,
@ -51,8 +51,8 @@ def test_complete_treasure_map_journey(federated_alice, federated_bob, federated
for ursula_address, encrypted_kfrag in treasure_map.destinations.items(): for ursula_address, encrypted_kfrag in treasure_map.destinations.items():
assert ursula_address in ursula_rolodex assert ursula_address in ursula_rolodex
ursula = ursula_rolodex[ursula_address] ursula = ursula_rolodex[ursula_address]
mock_kfrag_payload = encrypted_kfrags[ursula.checksum_address] kfrag_payload = encrypted_kfrags[ursula.checksum_address]
assert mock_kfrag_payload == ursula.verify_from(federated_alice, encrypted_kfrag, decrypt=True) # FIXME: 2203 assert kfrag_payload == ursula.verify_from(federated_alice, encrypted_kfrag, decrypt=True) # FIXME: 2203
serialized_map = bytes(treasure_map) serialized_map = bytes(treasure_map)
# ... # ...
@ -67,16 +67,16 @@ def test_complete_treasure_map_journey(federated_alice, federated_bob, federated
@pytest.mark.skip(reason='Backwards-incompatible with umbral 0.2+') @pytest.mark.skip(reason='Backwards-incompatible with umbral 0.2+')
def test_treasure_map_versioning(mocker, federated_alice, federated_bob, federated_ursulas): def test_treasure_map_versioning(mocker, federated_alice, federated_bob, federated_ursulas, idle_federated_policy):
# Produced using f04d564a1 # Produced using f04d564a1
map_from_previous_version = b'\x87T\x19\xceV_1\x8e\xb0\x87\xf6\xd9\x9d\x80\xba\xaf\xc4\x84\xa1\xd9|P=\x02\x13\xa0r1\x9eB\xf4\xfc\xc6w\xdf\xd1\x88\xc4\x83\x8f \x1c|\xec\xfcnW~k\x95f8\x19\r\xb1\xad\xe9\xa8\xc9\x06\x93j\xaf\xc50&[\xe5Cy\x9cr_R\xcd\xb1\xb1F\xed\x01\x00\x00\x02\xf4\x02][\xb8VP\xfa%D\xc3\xeb\xd4\x8b\xd2SW\x0f\xfe\xe5\x0f\xaa\xe6\x83\x9a\xa1\x91\xf6\x8e\xca\x00\x95\xf9\x90\x02-\x7f\xca\xe8$L\xcd0\x1d\xa1D\x80\xafjY\xea2\xbc\x04\x94\x1c\xd6E\xa4l\x8fu\xdf\x8a#\x04\xe1\x8eKN\xc9Y\xfbB7I\x9b\xa153\xcef\xfd\xb2/9[\x1b^\xe3\xcf\x08/\xf4%k\x06\xf4\xa5\x03\xfa\xf1\xdc\xec\xe1\t\xeb%\x0c\x11{\xbb\xc7Z\xb2^\x1d.\x18\xeaJ\xaa\xa6f\xd8\xb0\x92U\x84;\xbe6\x00\x00\x02m\x89\x97?\xcavL\xa7q\x13\x01\x1e\x1f6\x05)\xc2?\xcd\x96\xafhH/>6\x8d\x1a\xf8\xfd\xd5\x8a\xf9e\xb0\xc5\xa8\xbd(\x86\x9f\xb9L\xb9n=\xcb\xa0\xd2\t\x94\x90l\xc0\xb7\x85\x90N\xe0\xc9M{\x08\xc4\xf5\x80\xb7\xd1\x10\x18P\x8bl\x0f\x87fS\x836\xa6q\'\xabr\xd1l\x1e\xe2\xe7\xce\xccZ1[\x0b\xe7\xaa\x9c\x92Qh"2F\x1f\x9f-7HylC\xad\x03\x8ek_\xb6M\x19\xb2\xef\xde~\xa6\x10F<\xac\x94\xa6e\xc3\xb5\x132\x94\x96\xc4\xd9\'\xf9h\x1c\xe8\xb8Zm\x86M\xed\x00\x86\xc3\xf4\x93\x03/J\x1d6$\x1a\xe5+\xad\xf93\x17n\xc3\x19sQ2C\xaf\x9d\x89p\xb9557O\x9a\xc3O\xf0\x1f\xb3M.\xa9\x89\xeb\xb9\xf6\xe8\xcc@\xb0\\)\x9d\xdb\'\xfc\xc4_\xfd\xe1\xef\x01\xe3\xe7va\xac\xd7y\xb2\xcfm\xda\x85\x06(\x92H\xe2p\xf1\x9aw\xaf\x83\x1c\xd3@a\xaa\xf6\xee\xfc\xae&;\xdd*\x94I\'r1JG\xca\xdb\x9e\xef\x18Z\x9f\x15\x81\xe3\x1c\xcfJ\xd6;2H\xe8\xed\xfc\x98\x8e\xc6\x94\x1f\x1d\x95A\xa5\x8e\xe5\xc6f\x85\xbb\xc3\xd0\x9d\x83\xd3\xdf\x91]\x16\xe6)\xfa\xc0\xf3\xba\x7fAb\x81\xe0\x8f\x1bu0\x0b\x82^\xe9\x16\xf0\xfc\xc3p\xd4\x9f\'\xa6\xe5\xb4\xf7\xe1\x99\xa5\xfe\x12\x0e{L\xb0\xd6\xa1\x049\xcf\xe0\xca\x06\xe3\xd6u\x9e\xb3P\xb7\x1a\xc5X\xb7\xb2\xfa\x1dJ\xe1\xa9Gb\xf6l~DG\x8e5X\xc2^\x87\xac\x89W(\xaf\xd3\x15o\xde\xf7\xe4\x18\xd9\x98\xc3\tcL\xd3\x9dF\x8e3\xe5u\x03\x0b\xe7\tj\xdb\xd3B\xa1\x85\x9d \x9c\xa4{n\x01"\xab\xe1509\xdaoL\xc9\x8d\xc9\xfd"\xad\xd8\xfd\xf5\x14\xa2\xa8N\xf5\xa0\xf4\x04Y\x85i\xe0zj34\xc9\xbd\xac\xb9gn\x19J]\x0eL\x81C\xb9\x95\x86Q,\x81\xdf\xcbh\x13\xae8\xe8\x06y\xd1\xcd\x867\x1a\x1c\xe1\x05\xba\xfaL\x1a\x1f\x9f~\x18O1p@\xee\xee\xc4\xed\x84%\xb4\xb4\x12\xb6\x81\x0c\xcamf.\x9c\xe1\xfe\xc4\x87I\'\xc7e\xc1\x7f\xeb\x9c\xe1\xca\xa5\r.\x15\xa8r\xa8\x82Q\x13\x99K\x12X3\x04\xbc\x99\x96\xf8\xc3\x1es\x0c\x85\x8d\xd3\xee\x1b^\xc8\xf5\x1d^\x1a&6#\xbc\xa8~wp}]8\xb5\xe6v\xa4D\xfe:\xb8<q\xd9\x02\xfa\x7f\xcfWA\xad\xd1#\xac\x8b\xd7\xff\xca\xf7[dm\x9b\x06\xcc\x03\x1b\xfa\xd1\xf6:\xad\x1c\xb6\xb8' map_from_previous_version = b'\x87T\x19\xceV_1\x8e\xb0\x87\xf6\xd9\x9d\x80\xba\xaf\xc4\x84\xa1\xd9|P=\x02\x13\xa0r1\x9eB\xf4\xfc\xc6w\xdf\xd1\x88\xc4\x83\x8f \x1c|\xec\xfcnW~k\x95f8\x19\r\xb1\xad\xe9\xa8\xc9\x06\x93j\xaf\xc50&[\xe5Cy\x9cr_R\xcd\xb1\xb1F\xed\x01\x00\x00\x02\xf4\x02][\xb8VP\xfa%D\xc3\xeb\xd4\x8b\xd2SW\x0f\xfe\xe5\x0f\xaa\xe6\x83\x9a\xa1\x91\xf6\x8e\xca\x00\x95\xf9\x90\x02-\x7f\xca\xe8$L\xcd0\x1d\xa1D\x80\xafjY\xea2\xbc\x04\x94\x1c\xd6E\xa4l\x8fu\xdf\x8a#\x04\xe1\x8eKN\xc9Y\xfbB7I\x9b\xa153\xcef\xfd\xb2/9[\x1b^\xe3\xcf\x08/\xf4%k\x06\xf4\xa5\x03\xfa\xf1\xdc\xec\xe1\t\xeb%\x0c\x11{\xbb\xc7Z\xb2^\x1d.\x18\xeaJ\xaa\xa6f\xd8\xb0\x92U\x84;\xbe6\x00\x00\x02m\x89\x97?\xcavL\xa7q\x13\x01\x1e\x1f6\x05)\xc2?\xcd\x96\xafhH/>6\x8d\x1a\xf8\xfd\xd5\x8a\xf9e\xb0\xc5\xa8\xbd(\x86\x9f\xb9L\xb9n=\xcb\xa0\xd2\t\x94\x90l\xc0\xb7\x85\x90N\xe0\xc9M{\x08\xc4\xf5\x80\xb7\xd1\x10\x18P\x8bl\x0f\x87fS\x836\xa6q\'\xabr\xd1l\x1e\xe2\xe7\xce\xccZ1[\x0b\xe7\xaa\x9c\x92Qh"2F\x1f\x9f-7HylC\xad\x03\x8ek_\xb6M\x19\xb2\xef\xde~\xa6\x10F<\xac\x94\xa6e\xc3\xb5\x132\x94\x96\xc4\xd9\'\xf9h\x1c\xe8\xb8Zm\x86M\xed\x00\x86\xc3\xf4\x93\x03/J\x1d6$\x1a\xe5+\xad\xf93\x17n\xc3\x19sQ2C\xaf\x9d\x89p\xb9557O\x9a\xc3O\xf0\x1f\xb3M.\xa9\x89\xeb\xb9\xf6\xe8\xcc@\xb0\\)\x9d\xdb\'\xfc\xc4_\xfd\xe1\xef\x01\xe3\xe7va\xac\xd7y\xb2\xcfm\xda\x85\x06(\x92H\xe2p\xf1\x9aw\xaf\x83\x1c\xd3@a\xaa\xf6\xee\xfc\xae&;\xdd*\x94I\'r1JG\xca\xdb\x9e\xef\x18Z\x9f\x15\x81\xe3\x1c\xcfJ\xd6;2H\xe8\xed\xfc\x98\x8e\xc6\x94\x1f\x1d\x95A\xa5\x8e\xe5\xc6f\x85\xbb\xc3\xd0\x9d\x83\xd3\xdf\x91]\x16\xe6)\xfa\xc0\xf3\xba\x7fAb\x81\xe0\x8f\x1bu0\x0b\x82^\xe9\x16\xf0\xfc\xc3p\xd4\x9f\'\xa6\xe5\xb4\xf7\xe1\x99\xa5\xfe\x12\x0e{L\xb0\xd6\xa1\x049\xcf\xe0\xca\x06\xe3\xd6u\x9e\xb3P\xb7\x1a\xc5X\xb7\xb2\xfa\x1dJ\xe1\xa9Gb\xf6l~DG\x8e5X\xc2^\x87\xac\x89W(\xaf\xd3\x15o\xde\xf7\xe4\x18\xd9\x98\xc3\tcL\xd3\x9dF\x8e3\xe5u\x03\x0b\xe7\tj\xdb\xd3B\xa1\x85\x9d \x9c\xa4{n\x01"\xab\xe1509\xdaoL\xc9\x8d\xc9\xfd"\xad\xd8\xfd\xf5\x14\xa2\xa8N\xf5\xa0\xf4\x04Y\x85i\xe0zj34\xc9\xbd\xac\xb9gn\x19J]\x0eL\x81C\xb9\x95\x86Q,\x81\xdf\xcbh\x13\xae8\xe8\x06y\xd1\xcd\x867\x1a\x1c\xe1\x05\xba\xfaL\x1a\x1f\x9f~\x18O1p@\xee\xee\xc4\xed\x84%\xb4\xb4\x12\xb6\x81\x0c\xcamf.\x9c\xe1\xfe\xc4\x87I\'\xc7e\xc1\x7f\xeb\x9c\xe1\xca\xa5\r.\x15\xa8r\xa8\x82Q\x13\x99K\x12X3\x04\xbc\x99\x96\xf8\xc3\x1es\x0c\x85\x8d\xd3\xee\x1b^\xc8\xf5\x1d^\x1a&6#\xbc\xa8~wp}]8\xb5\xe6v\xa4D\xfe:\xb8<q\xd9\x02\xfa\x7f\xcfWA\xad\xd1#\xac\x8b\xd7\xff\xca\xf7[dm\x9b\x06\xcc\x03\x1b\xfa\xd1\xf6:\xad\x1c\xb6\xb8'
kfrags = [os.urandom(32) for _ in range(3)] kfrags = idle_federated_policy.kfrags[:3]
treasure_map = TreasureMap.construct_by_publisher(publisher=federated_alice, treasure_map = TreasureMap.construct_by_publisher(publisher=federated_alice,
bob=federated_bob, bob=federated_bob,
label=b'still Bill', label=b'still Bill',
ursulas=list(federated_ursulas)[:len(kfrags)], ursulas=list(federated_ursulas)[:len(kfrags)],
kfrags=kfrags, verified_kfrags=kfrags,
m=2) m=2)
# Good version (baseline) # Good version (baseline)