{"id":372,"date":"2020-11-12T12:25:13","date_gmt":"2020-11-12T12:25:13","guid":{"rendered":"https:\/\/cupl.co.uk\/?page_id=372"},"modified":"2020-12-18T10:00:01","modified_gmt":"2020-12-18T10:00:01","slug":"cuplcodec-features","status":"publish","type":"page","link":"https:\/\/cupl.co.uk\/index.php\/software\/cuplcodec\/cuplcodec-features\/","title":{"rendered":"Features"},"content":{"rendered":"\n<div class=\"wp-block-ugb-feature ugb-feature ugb-190923d ugb-feature--v2 ugb-feature--design-plain ugb-main-block\" id=\"\"><style>.ugb-190923d .ugb-inner-block{text-align:left}@media screen and (min-width:768px){.ugb-190923d .ugb-feature__item{grid-template-columns:1.18fr 0.82fr !important}.ugb-190923d .ugb-img{width:300px;height:auto !important}}<\/style><div class=\"ugb-inner-block\"><div class=\"ugb-block-content\"><div class=\"ugb-feature__item\"><div class=\"ugb-feature__content\"><h2 class=\"ugb-feature__title\">Tamper Resistant<\/h2><p class=\"ugb-feature__description\">The encoder takes an optional <a href=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/reference\/c_encoder\/nvtype.html#_CPPv4N8nvstruct6seckeyE\" data-type=\"URL\" data-id=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/reference\/c_encoder\/nvtype.html#_CPPv4N8nvstruct6seckeyE\">secret key<\/a>. This is <a href=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/specification\/features.html#CODEC_FEAT_24\" data-type=\"URL\" data-id=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/specification\/features.html#CODEC_FEAT_24\">combined<\/a> with other data stored in the URL to create a Hash Based Message Authentication Code (<a href=\"https:\/\/en.wikipedia.org\/wiki\/HMAC\" data-type=\"URL\" data-id=\"https:\/\/en.wikipedia.org\/wiki\/HMAC\">HMAC<\/a>). <br><br>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.<br><br>The secret key is stored on the <a href=\"https:\/\/cupl.co.uk\/index.php\/cuplTag\/\" data-type=\"URL\" data-id=\"https:\/\/cupl.co.uk\/index.php\/cuplTag\/\">cuplTag<\/a> 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. <br><br>The secret key is known only to the encoder and the decoder. The latter has it <a href=\"https:\/\/cupl.co.uk\/index.php\/software\/cuplbackend\/cuplbackend-consumer-api\/#capture-creation\" data-type=\"URL\" data-id=\"https:\/\/cupl.co.uk\/index.php\/software\/cuplbackend\/cuplbackend-consumer-api\/#capture-creation\">supplied<\/a> from a database, as part of a <a href=\"https:\/\/cupl.co.uk\/index.php\/cuplbackend\/\" data-type=\"page\" data-id=\"173\">larger application<\/a>. <br><br>The <a href=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/reference\/decoder\/index.html#wscodec.decoder.decoderfactory.decode\" data-type=\"URL\" data-id=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/reference\/decoder\/index.html#wscodec.decoder.decoderfactory.decode\">decoder<\/a> 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.<\/p><\/div><div class=\"ugb-feature__image-side\"><img class=\"ugb-feature__image ugb-img wp-image-418\" src=\"https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/key-300x300.jpg\" alt=\"\" height=\"300\" srcset=\"https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/key-300x300.jpg 300w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/key-100x100.jpg 100w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/key-600x601.jpg 600w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/key-1022x1024.jpg 1022w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/key-150x150.jpg 150w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/key-768x769.jpg 768w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/key.jpg 1200w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/div><\/div><\/div><\/div><\/div>\n\n\n\n<div class=\"wp-block-ugb-feature ugb-feature ugb-116cba1 ugb-feature--v2 ugb-feature--design-plain ugb-main-block\" id=\"\"><style>.ugb-116cba1 .ugb-inner-block{text-align:left}@media screen and (min-width:768px){.ugb-116cba1 .ugb-feature__item{grid-template-columns:1.18fr 0.82fr !important}.ugb-116cba1 .ugb-img{width:300px;height:auto !important}}<\/style><div class=\"ugb-inner-block\"><div class=\"ugb-block-content\"><div class=\"ugb-feature__item\"><div class=\"ugb-feature__content\"><h2 class=\"ugb-feature__title\">Testable<\/h2><p class=\"ugb-feature__description\">Testing this codec is straightforward: the decoder output must equal the encoder input. <br><br>The list of samples <em>out <\/em>of the codec must equal the list <em>in<\/em> (up to the size of the circular buffer).<br><br>Both the decoder and encoder are callable from a Python script. Tests utilise the <a href=\"https:\/\/docs.pytest.org\/en\/stable\/contents.html#\" data-type=\"URL\" data-id=\"https:\/\/docs.pytest.org\/en\/stable\/contents.html#\">pytest<\/a> framework.  The encoder itself is written in C. <a href=\"https:\/\/cffi.readthedocs.io\/en\/latest\/\" data-type=\"URL\" data-id=\"https:\/\/cffi.readthedocs.io\/en\/latest\/\">CFFI<\/a> was used to create <a href=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/reference\/pyencoder\/index.html\" data-type=\"URL\" data-id=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/reference\/pyencoder\/index.html\">pyEncoder<\/a>, which acts as a wrapper.<br><br>When the <a href=\"https:\/\/pypi.org\/project\/cuplcodec\" data-type=\"URL\" data-id=\"https:\/\/pypi.org\/project\/cuplcodec\">cuplcodec package<\/a> 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.<\/p><\/div><div class=\"ugb-feature__image-side\"><img class=\"ugb-feature__image ugb-img wp-image-416\" src=\"https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/shutterstock_705672271-2-300x300.jpg\" alt=\"\" height=\"300\" srcset=\"https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/shutterstock_705672271-2-300x300.jpg 300w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/shutterstock_705672271-2-100x100.jpg 100w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/shutterstock_705672271-2-600x600.jpg 600w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/shutterstock_705672271-2-1024x1024.jpg 1024w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/shutterstock_705672271-2-150x150.jpg 150w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/shutterstock_705672271-2-768x768.jpg 768w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/shutterstock_705672271-2.jpg 1200w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/div><\/div><\/div><\/div><\/div>\n\n\n\n<div class=\"wp-block-ugb-feature ugb-feature ugb-1a1fda1 ugb-feature--v2 ugb-feature--design-plain ugb-main-block\" id=\"\"><style>@media screen and (min-width:768px){.ugb-1a1fda1 .ugb-img{width:300px;height:auto !important}}<\/style><div class=\"ugb-inner-block\"><div class=\"ugb-block-content\"><div class=\"ugb-feature__item\"><div class=\"ugb-feature__content\"><h2 class=\"ugb-feature__title\">Relative Timestamps<\/h2><p class=\"ugb-feature__description\">The encoder runs on a <a href=\"https:\/\/cupl.co.uk\/index.php\/cuplTag\/\" data-type=\"URL\" data-id=\"https:\/\/cupl.co.uk\/index.php\/cuplTag\/\">cuplTag<\/a>, which is   <a href=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/specification\/requirements.html#CODEC_REQ_7\" data-type=\"URL\" data-id=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/specification\/requirements.html#CODEC_REQ_7\">required<\/a> to<em> <\/em><strong>just work<\/strong> 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!<br><br>In place of an absolute timestamp, the encoder takes two arguments:<\/p><\/div><div class=\"ugb-feature__image-side\"><img class=\"ugb-feature__image ugb-img wp-image-423\" src=\"https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/old_stopwatch2-300x300.jpg\" alt=\"\" height=\"300\" srcset=\"https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/old_stopwatch2-300x300.jpg 300w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/old_stopwatch2-100x100.jpg 100w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/old_stopwatch2-600x601.jpg 600w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/old_stopwatch2-1022x1024.jpg 1022w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/old_stopwatch2-150x150.jpg 150w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/old_stopwatch2-768x769.jpg 768w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/old_stopwatch2.jpg 1200w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/div><\/div><\/div><\/div><\/div>\n\n\n\n<ol><li>Time interval between samples in minutes \u0394T.<\/li><li>Elapsed minutes since the most recent sample T<sub>e<\/sub>.<\/li><\/ol>\n\n\n\n<p>T<sub>e<\/sub> is essential for timestamps to be accurate to +\/- 1 minute, which is good enough in most cases. <\/p>\n\n\n\n<p>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-T<sub>e<\/sub>. A multiple of \u0394T is subtracted for each preceding sample. <\/p>\n\n\n\n<p>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.<\/p>\n\n\n\n<div class=\"wp-block-ugb-feature ugb-feature ugb-e80aa20 ugb-feature--v2 ugb-feature--design-plain ugb-main-block\" id=\"\"><style>@media screen and (min-width:768px){.ugb-e80aa20 .ugb-img{width:300px;height:auto !important}}<\/style><div class=\"ugb-inner-block\"><div class=\"ugb-block-content\"><div class=\"ugb-feature__item\"><div class=\"ugb-feature__content\"><h2 class=\"ugb-feature__title\">Battery Level<\/h2><p class=\"ugb-feature__description\">The cupl URL incorporates a <a href=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/specification\/specs.html#CODEC_SPEC_15\" data-type=\"URL\" data-id=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/specification\/specs.html#CODEC_SPEC_15\">status parameter<\/a>, 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. <br><br>There are also data for diagnosing a failure: the cause of the most recent microcontroller reset and how many have occurred. <br><br><\/p><\/div><div class=\"ugb-feature__image-side\"><img class=\"ugb-feature__image ugb-img wp-image-429\" src=\"https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/battery_illustration_small-300x300.jpg\" alt=\"\" height=\"300\" srcset=\"https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/battery_illustration_small-300x300.jpg 300w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/battery_illustration_small-100x100.jpg 100w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/battery_illustration_small-600x601.jpg 600w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/battery_illustration_small-1022x1024.jpg 1022w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/battery_illustration_small-150x150.jpg 150w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/battery_illustration_small-768x769.jpg 768w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/battery_illustration_small.jpg 1200w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/div><\/div><\/div><\/div><\/div>\n\n\n\n<div class=\"wp-block-ugb-feature ugb-feature ugb-676619c ugb-feature--v2 ugb-feature--design-plain ugb-main-block\" id=\"\"><style>@media screen and (min-width:768px){.ugb-676619c .ugb-img{width:300px;height:auto !important}}<\/style><div class=\"ugb-inner-block\"><div class=\"ugb-block-content\"><div class=\"ugb-feature__item\"><div class=\"ugb-feature__content\"><h2 class=\"ugb-feature__title\">Flash and Battery Friendly<\/h2><p class=\"ugb-feature__description\">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 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Wear_leveling\" data-type=\"URL\" data-id=\"https:\/\/en.wikipedia.org\/wiki\/Wear_leveling\">wear leveling<\/a>.<br><br>The part of the cupl URL that contains sample data is a <a href=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/specification\/specs.html#CODEC_SPEC_12\" data-type=\"URL\" data-id=\"https:\/\/wscodec.readthedocs.io\/en\/dev\/docs\/specification\/specs.html#CODEC_SPEC_12\">circular buffer<\/a>, 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.<\/p><\/div><div class=\"ugb-feature__image-side\"><img class=\"ugb-feature__image ugb-img wp-image-445\" src=\"https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/flash-300x238.png\" alt=\"\" height=\"238\" srcset=\"https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/flash-300x238.png 300w, https:\/\/cupl.co.uk\/wp-content\/uploads\/2020\/11\/flash.png 472w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/div><\/div><\/div><\/div><\/div>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":171,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"inline_featured_image":false,"spay_email":""},"featured_image_urls":{"full":"","thumbnail":"","medium":"","medium_large":"","large":"","1536x1536":"","2048x2048":""},"post_excerpt_stackable":"<p>Tamper ResistantThe 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&hellip;<\/p>\n","category_list":"","author_info":{"name":"malcolmmackay","url":"https:\/\/cupl.co.uk\/index.php\/author\/malcolmmackay\/"},"comments_num":"0 comments","featured_image_urls_v2":{"full":"","thumbnail":"","medium":"","medium_large":"","large":"","1536x1536":"","2048x2048":""},"post_excerpt_stackable_v2":"<p>Tamper ResistantThe 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&hellip;<\/p>\n","category_list_v2":"","author_info_v2":{"name":"malcolmmackay","url":"https:\/\/cupl.co.uk\/index.php\/author\/malcolmmackay\/"},"comments_num_v2":"0 comments","_links":{"self":[{"href":"https:\/\/cupl.co.uk\/index.php\/wp-json\/wp\/v2\/pages\/372"}],"collection":[{"href":"https:\/\/cupl.co.uk\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/cupl.co.uk\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/cupl.co.uk\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cupl.co.uk\/index.php\/wp-json\/wp\/v2\/comments?post=372"}],"version-history":[{"count":59,"href":"https:\/\/cupl.co.uk\/index.php\/wp-json\/wp\/v2\/pages\/372\/revisions"}],"predecessor-version":[{"id":835,"href":"https:\/\/cupl.co.uk\/index.php\/wp-json\/wp\/v2\/pages\/372\/revisions\/835"}],"up":[{"embeddable":true,"href":"https:\/\/cupl.co.uk\/index.php\/wp-json\/wp\/v2\/pages\/171"}],"wp:attachment":[{"href":"https:\/\/cupl.co.uk\/index.php\/wp-json\/wp\/v2\/media?parent=372"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}