def receive_message(self, sender, message_metadata, other_recipients=None):
        """
        Interpret incoming additional data

        :param sender: Sender identifier
        :param message_metadata: Additional data obtained by ``send_message``
        :param other_recipients: Identifiers of other known recipients of the
                                 message
        """
        logger.debug('%s <- %s', self.email, sender)
        if other_recipients is None:
            other_recipients = set()

        with self.params.as_default():
            # Merge stores temporarily.
            merged_store = ObjectStore(self.gossip_store)
            for key, obj in message_metadata.store.items():
                merged_store[key] = obj

            sender_head = message_metadata.head
            sender_latest_block = merged_store[sender_head]
            self.gossip_store[sender_head] = \
                    sender_latest_block
            self.expected_views[sender] = View(
                Chain(self.gossip_store, root_hash=sender_head))
            full_sender_view = View(Chain(merged_store, root_hash=sender_head))
            logger.debug('%s / expected view / %s', self.email, sender)

            # Add relevant objects from the message store.
            contacts = self.get_accessible_contacts(sender, message_metadata,
                                                    other_recipients)
            for contact in contacts - {self.email}:
                contact_head = self.get_contact_head_from_view(
                    full_sender_view, contact)
                if contact_head is None:
                    continue
                contact_latest_block = message_metadata.store.get(contact_head)
                if contact_latest_block is not None:
                    self.gossip_store[contact_head] = contact_latest_block

                # NOTE: Assumes people send only contacts' latest blocks
                contact_chain = Chain(self.gossip_store,
                                      root_hash=contact_head)
                self.global_views[sender][contact] = View(contact_chain)

            # TODO: Needs a special check for contact==self.email.

            # Recompute the latest beliefs.
            for contact in {sender} | contacts:
                self.get_latest_view(contact)
예제 #2
0
def test_read_claim_from_other_chain():
    for i in range(1, 100):
        alice_params = LocalParams.generate()
        alice_state = State()
        alice_store = {}
        alice_chain = Chain(alice_store, None)
        alice_state.identity_info = "Hi, I'm " + pet2ascii(alice_params.dh.pk)
        with alice_params.as_default():
            alice_head = alice_state.commit(alice_chain)
        alice_chain = Chain(alice_store, alice_head)

        bob_params = LocalParams.generate()
        bob_state = State()
        bob_store = {}
        bob_chain = Chain(bob_store, None)
        bob_state.identity_info = "Hi, I'm " + pet2ascii(bob_params.dh.pk)
        with bob_params.as_default():
            bob_head = bob_state.commit(bob_chain)
        bob_chain = Chain(bob_store, bob_head)

        bob_pk = bob_params.dh.pk

        with alice_params.as_default():
            alice_state[b"bobs_key"] = b"123abc"
            alice_state.grant_access(bob_pk, [b"bobs_key"])
            alice_head = alice_state.commit(alice_chain)
        alice_chain = Chain(alice_store, alice_head)

        with alice_params.as_default():
            value = View(alice_chain)[b'bobs_key'].decode('utf-8')

        assert value == "123abc"

        with bob_params.as_default():
            value = View(alice_chain)[b'bobs_key'].decode('utf-8')

        assert value == "123abc"
예제 #3
0
 def process_incoming_gossip(self, addr2pagh, account_key, dec_msg):
     root_hash = dec_msg["GossipClaims"]
     store = FileStore(dec_msg["ChainStore"])
     peers_chain = Chain(store, root_hash=ascii2bytes(root_hash))
     assert peers_chain
     view = View(peers_chain)
     peers_pk = view.params.dh.pk
     assert peers_pk
     sender = parse_email_addr(dec_msg["From"])
     self.addr2root_hash[sender] = root_hash
     self.addr2pk[sender] = peers_pk
     recipients = get_target_emailadr(dec_msg)
     for recipient in recipients:
         pagh = addr2pagh[recipient]
         value = self.read_claim_from(peers_chain, recipient)
         if value:
             # for now we can only read claims about ourselves...
             # so if we get a value it must be our head imprint.
             assert value == bytes2ascii(pagh.keydata)
예제 #4
0
    def __init__(self, email):
        self.email = email
        self.params = LocalParams.generate()
        self.chain_store = ObjectStore()
        self.tree_store = ObjectStore()
        self.chain = Chain(self.chain_store)
        self.state = State()

        # Stats
        self.nb_sent_emails = 0
        self.date_of_last_key_update = None

        # Committed views and capabilities
        self.committed_caps = {}
        self.committed_views = {}
        # ...and the ones queued to be committed.
        self.queued_identity_info = None
        self.queued_caps = defaultdict(set)
        self.queued_views = {}
        # Capabilities for unknown yet contacts
        # and views that have no readers.
        self.expected_caps = defaultdict(set)
        self.expected_views = defaultdict(set)

        # Known beliefs of other people about other people.
        self.global_views = defaultdict(dict)
        # Contacts that senders have made available to this agent.
        self.contacts_by_sender = defaultdict(set)

        # Objects that were sent to each recipient.
        self.sent_object_keys_to_recipients = {}
        # Objects that were received from other people.
        self.gossip_store = ObjectStore()

        # Generate initial encryption key, and add first block
        # to the chain
        self.update_key()
예제 #5
0
 def chain(self):
     return Chain(self.store, root_hash=self._head)
예제 #6
0
 def get_chain(self, store_url, root_hash):
     cache_dir = os.path.join(self.accountdir, 'cache')
     store = FileStore(cache_dir, store_url)
     return Chain(store, root_hash=ascii2bytes(root_hash))
예제 #7
0
 def make(self, block_cls=BaseBlock):
     return Chain(object_store, block_cls=block_cls)
예제 #8
0
 def _get_current_chain(self):
     return Chain(self.store, root_hash=self.head)
예제 #9
0
def test_e2e_timings():
    friends_graph, all_data = generate_test_data()
    (labels, heads, pubkeys, privkeys) = all_data

    with LocalParams.generate().as_default() as params:
        nonce = os.urandom(PublicParams.get_default().nonce_size)

        # Encode claims
        t0 = time.time()
        c0 = 0
        enc_claims = []
        vrfs = []
        for claim_label, claim_body in zip(labels, heads):
            c0 += 1
            c0 += 1
            enc = encode_claim(nonce, claim_label, claim_body)
            vrf_value, lookup_key, encrypted_claim = enc
            enc_claims += [(lookup_key, encrypted_claim)]
            vrfs += [vrf_value]
        t1 = time.time()
        print("\n\t\tTiming per encoded claim: %1.1f ms" %
              ((t1 - t0) / c0 * 1000))

        # Encode capabilities
        t0 = time.time()
        c0 = 0
        capabilities = []
        cap_index = {}
        for friend in friends_graph:
            friend_dh_pk = pubkeys[friend]
            for fof in friends_graph[friend]:
                c0 += 1
                claim_label = labels[fof]
                vrf_value = vrfs[fof]
                cap_lookup_key, encrypted_cap = encode_capability(
                    friend_dh_pk, nonce, claim_label, vrf_value)
                capabilities += [(cap_lookup_key, encrypted_cap)]
                cap_index[(friend, fof)] = (cap_lookup_key, encrypted_cap)
        t1 = time.time()
        print("\t\tTiming per encoded capab: %1.1f ms" %
              ((t1 - t0) / c0 * 1000))

        data = encode([enc_claims, capabilities])
        print("\t\tData length: %1.1f kb" % (len(data) / 1024.0))

        # Build our non-equivocable tree
        t0 = time.time()
        tree = Tree()
        for lookup_key, enc_item in enc_claims + capabilities:
            tree.add(key=lookup_key, item=enc_item)
            _, evidence = tree.evidence(key=lookup_key)
            assert tree.is_in(enc_item, key=lookup_key)
            enc_item_hash = evidence[-1].item
            tree.store[enc_item_hash] = enc_item

        t1 = time.time()
        print("\t\tTiming for building non-equiv. tree: %1.1f ms" %
              ((t1 - t0) * 1000))

        # Build a chain and a block
        t0 = time.time()
        c0 = 200
        for _ in range(c0):
            chain = Chain(tree.store)
            payload = Payload.build(tree, nonce).export()

            def sign_block(block):
                sig = sign(block.hash())
                block.aux = pet2ascii(sig)

            chain.multi_add([payload], pre_commit_fn=sign_block)

            # Pack block
            block = chain.store[chain.head]
            packed_block = packb(
                ("S", block.index, block.fingers, block.items, block.aux))

        t1 = time.time()

        print("\t\tTiming for building a block: %1.1f ms" %
              ((t1 - t0) / c0 * 1000))
        print("\t\tPacked block size: %d bytes" % (len(packed_block)))

        t0 = time.time()
        c0 = 0

        # Pick a random reader
        for reader in friends_graph:
            reader_params = LocalParams(
                dh=Keypair(sk=privkeys[reader], pk=pubkeys[reader]))
            for reader_friend in friends_graph[reader]:
                claim_label = labels[reader_friend]
                with reader_params.as_default():
                    view = View(chain)
                    c0 += 1
                    head = view[labels[reader_friend]]
                    assert head == heads[reader_friend]

        t1 = time.time()
        print("\t\tTiming for retrieving a claim by label: %1.1f ms" %
              ((t1 - t0) / c0 * 1000))

        # Pick a target proof to produce
        f1 = random.choice(list(friends_graph.keys()))
        f2 = random.choice(list(friends_graph[f1]))

        (cap_lookup_key, encrypted_cap) = cap_index[(f1, f2)]
        (claim_lookup_key, encrypted_claim) = enc_claims[f2]

        root, e1 = tree.evidence(key=cap_lookup_key)
        _, e2 = tree.evidence(key=claim_lookup_key)

        evidence_store = {e.identity(): e for e in e1 + e2}
        t2 = Tree(evidence_store, root)

        assert t2.is_in(key=cap_lookup_key, item=encrypted_cap)
        assert t2.is_in(key=claim_lookup_key, item=encrypted_claim)

        # Serialize evidence:
        evidence = []
        for e in e1 + e2:
            if isinstance(e, Leaf):
                evidence += [(e.key, e.item, tree.store[e.item])]
            elif isinstance(e, Branch):
                evidence += [(e.pivot, e.left_branch, e.right_branch)]
            else:
                pass

        import zlib
        bin_evidence = encode(evidence)
        bin_evidence_compressed = zlib.compress(bin_evidence, 9)
        print("\t\tSize for one proof: %s bytes (compressed %s bytes)" %
              (len(bin_evidence), len(bin_evidence_compressed)))

        print("\t\tPayload:")
        pprint(payload)