Skip to content

Engineer implementation details DRAFT

Rodrigo Kumpera edited this page May 12, 2020 · 1 revision

****This cover implementation details of a bunch of aspects.

Crypto ID protocol

  • hashing function: SHA-256
  • ID update schedule: 15 minutes.

EVERYWHERE in this document when we say ID it's referring to this crypto ID.

Implementation

Initial seeds are generated by reading 16 bytes from /dev/random.

At time-step T we compute ID T and SEED T+1in the following way:

hash = SHA256(id_t)
seed_t+1 = hash[0:16]
id_t = hash[16:32]

At all time, the timestamp to use use is an Unix epoch with seconds resolution.

We store pairs (seed, timestamp) in strict chronological order. Only initial seeds must be stored.

We don't need to save any ID but the original one since they can be regenerated. Implementations are free to save intermediate ones, even though the computation cost is negligible and only required at startup.

The way to generate an id is the following:

refresh_interval = 15 * 60; //as per above
get_current_id(seed, seed_timestamp)
{
  steps = (current_time - seed_timestamp) / refresh_interval; //interger division, must round down.
  for(int i = 0; i < steps; ++i) {
     hash = SHA256([seed, seed]);
     seed = hash[0:16]
  }
  
  id = SHA256([seed, seed])[16:32];
 }

Open Questions

Should timestamps by aligned to the update schedule?

This is a question of whether timestamp % schedule == 0 needs to hold. ??

Do we need synchronized clocks? To what degree? How?

Time should be within a few minutes of correct time. (say 5 minutes maximum.) If drift of larger than this is going to be a frequent problem, we need to figure out a way to rectify the error when we are publishing to the database. When the database is read, any IDs which are more than 20 minutes from their claimed time for announcement will be ignored since they maybe a replay attack. We get an implied time sync when we write to the database (which we assume knows accurate time). So maybe we should read the time from the database, sync our clock to that time and adjust any times we have to the database time and then write to the database. That way we only need to have accurate times when we are writing to the database.

BLE networking

  • Service ID: 8cf0282e-d80f-4eb7-a197-e3e0f965848d
  • Characteristic ID: d945590b-5b09-4144-ace7-4063f95bd0bb

Basics

Active tracing happens when the device find others through BLE scanning.

Passive tracing happens when another device reaches out and send their ID to us.

RSSI stands for Received Signal Strength Indicator and it's currently our best indicator of physical proximity.

Devices must

  • Send their IDs every 5 minutes to devices within range.
  • Read other devices IDs every 10 minutes.
  • Record active contact traces every 1 minute.
  • Record passive contact traces on demand.
  • Timeout connection attempts after 5 seconds.
  • Close connections right after data exchange completes.
  • Announce the contacts service permanently.
  • Scan for other devices at least every 1 minute.

Devices may/should

  • Cull networking based on RSSI or better proximity measurements.
  • Cache device information based on UUID for up to 60 minutes.
  • Retry networking communication in case of failure.
  • Permanently scan for other devices.

Active tracing

BLE scanning happens at a higher frequency than we need for tracing. So we record contacts with a fixed time. During that period we should collect all sensed RSSI and report the strongest one.

Writes should happen at the ID exchange frequency specified above. A write should only be initiated if the other device RSSI fits the criteria of close enough.

Reads can be avoided and use cached data based on the device UUID. The cache should respect the defined expiration limit.

The value RSSI is used to filter those devices considered to be too distant to matter. Active tracing just record those proximity events and leave the judgement of their value for other parts of the system.

Passive tracing

We log every passive contact as it's not easy to sense their RSSI and make a judgement on distance.

Aggregation based on the exchange timing is optional for now, it's ok to trust the other party to respect it.

The Characteristic must

  • Return the device ID when read.
  • Record a remove device ID when written to.
  • Have read+write properties.
  • Have read+write permissions.

The Service must

  • Announce the characteristic.

Write payload

To send the device ID to another device a single write of 16 bytes must be used. Those 16 bytes must include the ID as specified earlier.

iOS Implementation

On iOS we read/write to all devices it finds through scanning only.

Open Questions

The IDs we're using don't match other efforts. Should we be compatible?

??

What RSSI values do we consider to be "close enough"?

-82. Ran a test with multiple Android phones at 2m. This was the mean of all measurements. (DPF: We don't have to have pass-fail grading here. Biologically we are looking for an accumulation of enough exposure so that it makes economic sense to take a test. Ideally we would use something like the the total of 1/(1+distance) over all times and all infected IDs. Approximating this function by 1 if distance<2, and 0 if distance > 2 is easy to explain--but likely bad biology. So I'd be happier with maybe 3 levels, far=more than 5 meters, medium=between 2 and 5 meters and close=less than 2 meters. And then discard the far, count the medium for 1/2 and count the close for 1. THen we can sum over all exposures and see if we have a total of about 15 minutes of exposure. If so, we tell the user. THis 15 minutes number will change as testing gets cheaper and there are fewer infected people wandering around.)

Should we write the sender-side RSSI?

??

Write requests have the Bluetooth UUID of the sender. Should we filter on that?

??

File formats

Misc. details

  • Infection period is 14 days

  • Minimum and maximum GPS resolution (2 decimal points and 5 decimal points)

  • Frequency at which healthy users poll server: 1 hour (DPF: This should be much more frequent. You want to get new ID within a few minutes. These should be fairly cheap since mostly they will get back a message--no new data.)

  • Maximum number of seeds that can be queried in a single server poll: 100?

  • Make sure we any logic handles the case that a user may turn off the phone at any point

  • Make sure that any timestamp we receive from the server is in the past and not in the future. Make sure we place a bound on the total number of UUIDs that are generated.

  • The infected user should send their last collected GPS point at maximum resolution (5 points) (DPF: I didn't think we were doing anything with GPS at all.)

  • The potentially exposed user should poll from the server every 1 hour

  • The infected user should send a timestamp at some maximum resolution (let's say 5 decimal points)

  • The healthy user should begin polling the server with a resolution of 2 decimal points up to 5 decimal points

  • A DOS attack is possible if someone marks an infection say 10,000 times in the same GPS location. People querying from that location will be unable to download these traces because 10,000 will exceed the limit of the number of seeds we can download. What the backend should do is to send some random subset of these to the user to prevent a blackout.

  • Make sure we are meeting the CDC guideline of 10 minutes of exposure before bringing up a warning. To do this, we have to see that there are 2 consecutive UUID matches within some ~5 minute time frame, which corresponds to a 10 minute exposure. (DPF: If we are rotating every minute, then we want to simply accumulate all the matches. If we get 10 minutes of close matches, we don't care if they are from different people or the same person. We should recommend testing to the phone owner.)

Query implementation

  • Minimum GPS precision: 2 decimal points(?)
  • Maximum GPS precision: 5 decimal points(?)
  • Maximum number of seeds client is willing to accept in a single download: ?