Files
MicrOBU/microbu-esp32c5/external/vanetza-idf/vanetza/security/v2/length_coding.cpp
T
Ashin Walpola 0e9525162d Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
2026-09-23 17:46:40 +02:00

95 lines
2.7 KiB
C++

#include <vanetza/security/v2/length_coding.hpp>
#include <cassert>
#include <cmath>
#include <iterator>
#include <list>
namespace vanetza
{
namespace security
{
namespace v2
{
std::size_t count_leading_ones(uint8_t v)
{
std::size_t count = 0;
while ((v & 0x80) != 0) {
v <<= 1;
++count;
}
return count;
}
std::size_t length_coding_size(std::uintmax_t length) {
std::size_t size = 1;
while ((length & ~0x7f) != 0) {
// prefix enlongates by one additional leading "1" per shift
length >>= 7; // shift by 7
++size;
}
return size;
}
ByteBuffer encode_length(std::uintmax_t length)
{
static_assert(sizeof(std::uintmax_t) <= 8, "size of length type exceeds implementation capabilities");
std::list<uint8_t> length_info;
while (length != 0) {
length_info.push_front(static_cast<uint8_t>(length));
length >>= 8;
}
unsigned prefix_length = length_info.size();
if (prefix_length == 0) {
// Zero-size encoding
length_info.push_back(0x00);
}
else {
assert(prefix_length <= 8);
uint8_t prefix_mask = ~((1 << (8 - prefix_length)) - 1);
if ((length_info.front() & ~prefix_mask) != length_info.front()) {
// additional byte needed for prefix
length_info.push_front(prefix_mask);
}
else {
// enough free bits available for prefix
length_info.front() |= (prefix_mask << 1);
}
// Huge lengths have all bits set in leading prefix bytes
length_info.insert(length_info.begin(), prefix_length / 8, 0xff);
}
return ByteBuffer(length_info.begin(), length_info.end());
}
std::tuple<ByteBuffer::const_iterator, std::uintmax_t> decode_length(const ByteBuffer& buffer)
{
if (!buffer.empty()) {
std::size_t additional_prefix = count_leading_ones(buffer.front());
if (additional_prefix >= sizeof(std::uintmax_t)) {
// encoded length is wider than uintmax_t, we cannot represent this number
return std::make_tuple(buffer.begin(), 0);
} else if (buffer.size() > additional_prefix) {
uint8_t prefix_mask = (1 << (8 - additional_prefix)) - 1;
std::uintmax_t length = buffer.front() & prefix_mask;
for (std::size_t i = 1; i <= additional_prefix; ++i) {
length <<= 8;
length |= buffer[i];
}
auto start = buffer.begin();
std::advance(start, additional_prefix + 1);
return std::make_tuple(start, length);
}
}
return std::make_tuple(buffer.end(), 0);
}
} // namespace v2
} // namespace security
} // namespace vanextza