Tamper Resistant

The encoder takes an optional secret key. This is combined with other data stored in the URL to create a Hash Based Message Authentication Code (HMAC).

The encoder includes the HMAC with the cuplURL. It is updated whenever a new sample is added to the circular buffer. The decoder can then verify it with knowledge of the secret key.

The secret key is stored on the cuplTag microcontroller. It is not readily accessible to the end user. Moreover it cannot be deduced from the HMAC itself or any other part of the cuplURL. Without the secret key it is hard to spoof a cuplURL; the HMAC will always be wrong.

The secret key is known only to the encoder and the decoder. The latter has it supplied from a database, as part of a larger application.

The decoder uses its copy of the key to verify that the received HMAC corresponds with data in the rest of the URL. If it does not, then it points either to a breach in data integrity or message authenticity: an exception is raised.


Testing this codec is straightforward: the decoder output must equal the encoder input.

The list of samples out of the codec must equal the list in (up to the size of the circular buffer).

Both the decoder and encoder are callable from a Python script. Tests utilise the pytest framework. The encoder itself is written in C. CFFI was used to create pyEncoder, which acts as a wrapper.

When the cuplcodec package is produced, CFFI compiles C encoder using GCC on Debian Linux. pyEncoder is an integral part of cuplcodec. Without it, automatic testing is not possible. Even although the decoder is all Python and cross-platform, pyEncoder requires Debian Linux for now.

Relative Timestamps

The encoder runs on a cuplTag, which is required to just work after a battery is inserted. It does not need to be reconfigured outside of the factory. Nobody should have to set the time on an NFC tag, like they do on an oven!

In place of an absolute timestamp, the encoder takes two arguments:

  1. Time interval between samples in minutes ΔT.
  2. Elapsed minutes since the most recent sample Te.

Te is essential for timestamps to be accurate to +/- 1 minute, which is good enough in most cases.

The decoder is normally run on a web server, where an accurate absolute timestamp T is readily available. The timestamp of the most recent sample is calculated first as T-Te. A multiple of ΔT is subtracted for each preceding sample.

A phone scanning the tag is assumed to have an internet connection. In most cases this is a given. By consequence, there will be a negligible ~1s time delay between the phone reading the NFC tag and timestamps being assigned.

Battery Level

The cupl URL incorporates a status parameter, with a field for the tag battery level, which the decoder outputs in mV. This is measured occasionally; it reduces gradually over months and years.

There are also data for diagnosing a failure: the cause of the most recent microcontroller reset and how many have occurred.

Flash and Battery Friendly

The encoder writes the cupl URL into EEPROM (flash) memory. This can only be erased and overwritten ~500,000 times before it starts to fail. This might seem like a lot but there are around this many minutes in one year. Some data on the tag are updated each minute, so there is a need for wear leveling.

The part of the cupl URL that contains sample data is a circular buffer, so the same memory location is only overwritten a few times for every ~300 samples (the buffer length). Only a small part of EEPROM is overwritten for each new sample, so the microcontroller spends less time writing and more time sleeping. This significantly increases battery life.