Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ tracing:
seed `SKt` for efficiency. When an app owner is diagnosed with SARS-CoV-2,
their app uploads the corresponding seed `SKt`. Other apps use this seed to
regenerate the ephemeral Bluetooth identifiers, and check if they have seen
an identifier corresponding to an infected person.
an identifier corresponding to an affected person.
* *Unlinkable design*. In this design, `EphID`s are generated independently
from random seeds. When an app owner is diagnosed with SARS-CoV-2, their app
uploads the corresponding seeds for each `EphID` broadcast in a compact
representation. Other apps use this compact representation to check if they
have seen an identifier corresponding to an infected person.
have seen an identifier corresponding to an affected person.

*Difference with respect to the Android/iOS SDKs and backend implementations.*
The DP-3T project has also published
Expand Down Expand Up @@ -61,7 +61,7 @@ designs. These files follow a similar structure:
(`get_ephid_for_time`), to process an observation (`add_obseration`), to
output tracing information (`get_tracing_information`), and to process a
batch of tracing information to determine the number of contacts with
infected people (`matches_with_batch`). Both designs use the same interface
affected people (`matches_with_batch`). Both designs use the same interface
for this class

This code deliberately does _not_ implement any interactions with (simulated)
Expand Down
20 changes: 10 additions & 10 deletions dp3t/protocols/lowcost.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def __init__(self, time_key_pairs, release_time=None):

Args:
time_key_pairs ([(time, byte array)]): List of tracing keys of
infected people and the corresponding start times.
affected people and the corresponding start times.
release_time (int, optional): Release time in seconds since UNIX Epoch
when missing, defaults to current time

Expand All @@ -190,7 +190,7 @@ class ContactTracer:
computing the final risk score. Observations are represented by the
corresponding EphID, and we omit proximity metrics such as duration and
signal strength. Similarly, the risk scoring mechanism is simple. It only
outputs the number of unique infected EphIDs that have been observed.
outputs the number of unique affected EphIDs that have been observed.

Actual implementations will probably take into account extra information
from the Bluetooth backend to do better distance measurements, and
Expand Down Expand Up @@ -378,15 +378,15 @@ def get_tracing_information(
return start_contagious_day, tracing_key

def matches_with_key(self, key, start_time, release_time):
"""Count #contacts with infected person given person's day key
"""Count #contacts with affected person given person's day key

Args:
key (byte array): A 32-byte key of an infected person
key (byte array): A 32-byte key of an affected person
start_time (int): The first day (in UNIX epoch seconds) on which this key is valid
release_time (int): The publication time of the key

Returns:
int: How many epochs we saw EphIDs of the infected person
int: How many epochs we saw EphIDs of the affected person
"""

ephids_per_day = self._reconstruct_ephids(key, start_time, release_time)
Expand All @@ -412,22 +412,22 @@ def matches_with_key(self, key, start_time, release_time):
return nr_encounters

def matches_with_batch(self, batch):
"""Count #contacts with each infected person in batch
"""Count #contacts with each affected person in batch

Args:
batch (`obj`:TracingDataBatch): A batch of tracing keys

Returns:
int: How many EphIDs of infected persons we saw
int: How many EphIDs of affected persons we saw
"""

seen_infected_ephids = 0
seen_affected_ephids = 0
release_time = batch.release_time

for (start_time, key) in batch.time_key_pairs:
seen_infected_ephids += self.matches_with_key(key, start_time, release_time)
seen_affected_ephids += self.matches_with_key(key, start_time, release_time)

return seen_infected_ephids
return seen_affected_ephids

def housekeeping_after_batch(self, batch):
"""Update stored observations after processing batch.
Expand Down
24 changes: 12 additions & 12 deletions dp3t/protocols/unlinkable.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,18 +127,18 @@ def __init__(self, tracing_seeds, release_time=None):

Args:
tracing_seeds ([(reported_epochs, seeds)]): A list of reported epochs/seeds
per infected user
per affected user
release_time (optional): Release time of this batch
"""

# Compute size of filter and ensure we have enough capacity
nr_items = sum([len(epochs) for (epochs, _) in tracing_seeds])
capacity = int(nr_items * 1.2)

self.infected_observations = CuckooFilter(capacity, error_rate=CUCKOO_FPR)
self.affected_observations = CuckooFilter(capacity, error_rate=CUCKOO_FPR)
for (epochs, seeds) in tracing_seeds:
for (epoch, seed) in zip(epochs, seeds):
self.infected_observations.insert(
self.affected_observations.insert(
hashed_observation_from_seed(seed, epoch)
)

Expand All @@ -155,7 +155,7 @@ class ContactTracer:
computing the final risk score. Observations are represented by the
corresponding EphID, and we omit proximity metrics such as duration and
signal strength. Similarly, the risk scoring mechanism is simple. It only
outputs the number of unique infected EphIDs that have been observed.
outputs the number of unique affected EphIDs that have been observed.

Actual implementations will probably take into account extra information
from the Bluetooth backend to do better distance measurements, and
Expand Down Expand Up @@ -332,21 +332,21 @@ def get_tracing_information(self, first_contagious_time, last_contagious_time=No
return reported_epochs, self.get_tracing_seeds_for_epochs(reported_epochs)

def matches_with_batch(self, batch):
"""Check for contact with infected person given a published filter
"""Check for contact with affected person given a published filter

Args:
infected_observations: A (compact) representation of hashed
observations belonging to infected persons
affected_observations: A (compact) representation of hashed
observations belonging to affected persons

Returns:
int: How many EphIDs of infected persons we saw
int: How many EphIDs of affected persons we saw
"""

seen_infected_ephids = 0
seen_affected_ephids = 0

for (_, hashed_observations) in self.observations_per_day.items():
for hashed_observation in hashed_observations:
if hashed_observation in batch.infected_observations:
seen_infected_ephids += 1
if hashed_observation in batch.affected_observations:
seen_affected_ephids += 1

return seen_infected_ephids
return seen_affected_ephids
6 changes: 3 additions & 3 deletions examples/run_lowcost.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,12 @@ def main():
batch = TracingDataBatch([tracing_info_bob], release_time=release_time)

print("[Server -> Alice] Alice receives batch")
print(" * Alice checks if she was in contact with an infected person")
print(" * Alice checks if she was in contact with an affected person")

if alice.matches_with_batch(batch) > 0:
print(" * CORRECT: Alice's phone concludes she is at risk")
print(" * CORRECT: Alice's phone concludes she is exposed")
else:
print(" * ERROR: Alice's phone does not conclude she is at risk")
print(" * ERROR: Alice's phone does not conclude she is not exposed")
raise RuntimeError("Example code failed!")

print("\n[Alice] Runs housekeeping to update her observation store")
Expand Down
6 changes: 3 additions & 3 deletions examples/run_unlinkable.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ def main():
batch = TracingDataBatch([tracing_info_bob])

print("[Server -> Alice] Alice receives batch")
print(" * Alice checks if she was in contact with an infected person")
print(" * Alice checks if she was in contact with an affected person")

if alice.matches_with_batch(batch) > 0:
print(" * CORRECT: Alice's phone concludes she is at risk")
print(" * CORRECT: Alice's phone concludes she is exposed")
else:
print(" * ERROR: Alice's phone does not conclude she is at risk")
print(" * ERROR: Alice's phone does not conclude she is not exposed")
raise RuntimeError("Example code failed!")


Expand Down
8 changes: 4 additions & 4 deletions tests/test_protocols_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def test_contact_tracing_single_observation(protocol):
alice.next_day()
bob.next_day()

# Bob infected, get tracing keys
# Bob affected, get tracing keys
tracing_info_bob = bob.get_tracing_information(START_TIME)

# Pack into a batch, set release time to 4 days from start
Expand Down Expand Up @@ -124,7 +124,7 @@ def test_contact_tracing_multiple_observations(protocol):
alice.next_day()
bob.next_day()

# Bob infected, get tracing keys
# Bob affected, get tracing keys
tracing_info_bob = bob.get_tracing_information(START_TIME)

# Pack into a batch
Expand All @@ -151,7 +151,7 @@ def test_contact_tracing_contact_before_contagious(protocol):
alice.next_day()
bob.next_day()

# Bob infected, get tracing keys, day after Alice and Bob met
# Bob affected, get tracing keys, day after Alice and Bob met
start_of_being_contagious = START_TIME + timedelta(days=1)
tracing_info_bob = bob.get_tracing_information(start_of_being_contagious)

Expand All @@ -171,7 +171,7 @@ def test_contact_tracing_no_replay_after_release(protocol):
transmit_time = START_TIME + timedelta(minutes=20)
ephid_bob = bob.get_ephid_for_time(transmit_time)

# Bob infected, get tracing keys
# Bob affected, get tracing keys
start_of_being_contagious = START_TIME
tracing_info_bob = bob.get_tracing_information(start_of_being_contagious)

Expand Down