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)
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"
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)
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()
def chain(self): return Chain(self.store, root_hash=self._head)
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))
def make(self, block_cls=BaseBlock): return Chain(object_store, block_cls=block_cls)
def _get_current_chain(self): return Chain(self.store, root_hash=self.head)
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)