corncobs: Corny COBS encoding/decoding in Rust

Overview

corncobs: Corny COBS encoding/decoding in Rust

This crate provides Consistent Overhead Byte Stuffing (COBS) support for Rust programs, with a particular focus on resource-limited embedded no_std targets:

  • Provides both fast (buffer-to-buffer) and small (in-place or iterator-based) versions of both encode and decode routines.

  • Provides a const fn for computing the maximum encoded size for a given input size, so you can define fixed-size buffers precisely without magic numbers.

  • Has pretty good test coverage, Criterion benchmarks, and a honggfuzz fuzz testing suite to try to ensure code quality.

When to use this crate

COBS lets us take an arbitrary blob of bytes and turn it into a slightly longer blob that doesn't contain a certain byte, except as a terminator at the very end. corncobs implements the version of this where the byte is zero. That is, corncobs can take a sequence of arbitrary bytes, and turn it into a slightly longer sequence that doesn't contain zero except at the end.

The main reason you'd want to do this is framing. If you're transmitting a series of messages over a stream, you need some way to tell where the messages begin and end. There are many ways to do this -- such as by transmitting a length before every message -- but most of them don't support sync recovery. Sync recovery lets a receiver tune in anywhere in a stream and figure out (correctly) where the next message boundary is. The easiest way to provide sync recovery is to use a marker at the beginning/end of each message that you can reliably tell apart from the data in the messages. To find message boundaries in an arbitrary data stream, you only need to hunt for the end of the current message and start parsing from there. COBS can do this by ensuring that the message terminator character (0) only appears between messages.

Unlike a lot of framing methods (particularly SLIP), COBS guarantees an upper bound to the size of the encoded output: the original length, plus two bytes, plus one byte per 254 input bytes. corncobs provides the max_encoded_len function for sizing buffers to allow for worst-case encoding overhead, at compile time.

corncobs can be used in several different ways, each with different costs and benefits.

  • Encoding
    • encode_buf: from one slice to another; efficient, but requires 2x the available RAM.
    • encode_iter: incremental, using an iterator; somewhat slower, but requires no additional memory. (This can be useful in a serial interrupt handler.)
  • Decoding
    • decode_buf: from one slice to another; efficient, but requires 2x the available RAM.
    • decode_in_place: in-place in a slice; nearly as efficient, but overwrites incoming data.

Cargo features

No features are enabled by default. Embedded programmers do not need to specify default-features = false when using corncobs because who said std should be the default anyhow? People with lots of RAM, that's who.

Features:

  • std: if you're on one of them "big computers" with "infinite memory" and can afford the inherent nondeterminism of dynamic memory allocation, this feature enables routines for encoding to-from Vec, and an Error impl for CobsError.

Tips for using COBS

If you're designing a protocol or message format and considering using COBS, you have some options.

Optimizing for size: COBS encoding has the least overhead when the data being encoded contains 0x00 bytes, at least one for every 254 bytes sent. In practice, most data formats achieve this. However...

Optimizing for speed: COBS encode/decode, and particularly the corncobs implementation, goes fastest when data contains as few 0x00 bytes as possible -- ideally none. If you can adjust the data you're encoding to avoid zero, you can achieve higher encode/decode rates. For instance, in one of my projects that sends RGB video data, I just declared that red/green/blue value 1 is the same as 0, and made all the 0s into 1s, for a large performance improvement.

You might also like...
Rust library for developing safe canisters.

IC Kit This library provides an alternative to ic-cdk that can help developers write canisters and unit test them in their Rust code. Install Add this

MimiRust - Hacking the Windows operating system to hand us the keys to the kingdom with Rust.
MimiRust - Hacking the Windows operating system to hand us the keys to the kingdom with Rust.

MimiRust - Hacking the Windows operating system to hand us the keys to the kingdom with Rust. MimiRust is a program based on the wdigest attack vector

simple multi-threaded port scanner written in rust
simple multi-threaded port scanner written in rust

knockson simple multi-threaded port scanner written in rust Install Using AUR https://aur.archlinux.org/packages/knockson-bin/ yay -Syu knockson-bin M

Rust TLS/SSL certificate expiration date from command-line checker

Rust TLS/SSL certificate expiration date from command-line checker

Lightweight slowloris (HTTP DoS) implementation in Rust.
Lightweight slowloris (HTTP DoS) implementation in Rust.

slowlorust Lightweight slowloris (HTTP DoS) implementation in Rust. Slowloris is a denial-of-service attack program which allows an attacker to overwh

A simple port scanner built using rust-lang

A simple port scanner built using rust-lang

Safe Rust interface to the Vulkan API.

Magma: A strictly typed Vulkan API interface. Magma is a strictly typed Rust interface for the vulkan API. This means that whenever possible, the well

A rust program to bruteforce ZIP, PDF and some popular hashes.

Veldora A program to bruteforce zips, pdfs and some popular hashes. This is basically a rust version of bruttle, but a lot faster. Installation: git c

BGPKIT Parser aims to provides the most ergonomic MRT/BGP/BMP message parsing Rust API.
BGPKIT Parser aims to provides the most ergonomic MRT/BGP/BMP message parsing Rust API.

BGPKIT Parser aims to provides the most ergonomic MRT/BGP/BMP message parsing Rust API.

Comments
  • packet size 255, test case 10 of COBS wikipedia

    packet size 255, test case 10 of COBS wikipedia

    let mut input = [5; 255];
        input[253] = 0;
        input[254] = 100;
        let mut actual = vec![0; max_encoded_len(input.len())];
        let n = encode_buf(&input, &mut actual[..]);
    

    results: 254, 5,...., 5, 2, 100, 0, 0

    If this stream of bytes are transmitted in packets of max. 255 bytes. 254, 5, ...., 5 (253 counts of "5"), 2 will be in one packet.

    As you can see the "2" is shifted up to fill the first packet.

    So the correct encoding should be 254, 5, ...., 5, 1, 2, 100, 0

    In other words, to encode, split the bytes into 254-byte first, then split by ZERO.

    Here is a detailed explanation link: https://circuit4us.medium.com/coding-consistent-overhead-byte-stuffing-cobs-for-packet-data-e60d7a361cf

    opened by circuit4u-medium 2
  • Fix encode_buf when a maximal-length run is immediately followed by a zero

    Fix encode_buf when a maximal-length run is immediately followed by a zero

    Prior to this change, encode_buf() would erroneously omit an encoded zero byte if that zero byte was immediately preceded by a MAX_LEN-length run. In addition to a fix, this PR adds:

    • A test fixture with a buffer that triggers this case
    • A fuzz test comparing encode_buf against encode_iter (which handled this case correctly)
    • A fuzz test that round trips through encode_buf and decode_in_place
    opened by jgallagher 0
  • Feature request: Implement COBS/R

    Feature request: Implement COBS/R

    Please consider implementing COBS/R which is a small variant of COBS that can often eliminate the +1-byte encoding overhead of COBS. I have implemented it in C and in Python.

    opened by cmcqueen 0
  • Update to recent cobs.rs (nee postcard-cobs) release

    Update to recent cobs.rs (nee postcard-cobs) release

    Hi there @cbiffle, I've been working on re-mainlining postcard-cobs into cobs.rs/cobs.

    I've released v0.2.1, which addresses the panics you mentioned (e.g. "losing it's mind"). It will now gracefully decode with an included zero terminator, or with a full message missing just the zero terminator at the end (for back-compat).

    I'm happy to provide any more information or context you were missing in your readme, but it reads more as an opinion piece at a snapshot in time, so it didn't seem right for me to update it.

    I wasn't able to run the fuzzing tests, but hopefully they may now work as well.

    opened by jamesmunns 0
Owner
Cliff L. Biffle
I'm pretty into this stuff.
Cliff L. Biffle
An esoteric language/compiler written with Rust and Rust LLVM bindings

MeidoLang (メイドラング) A not so useful and esoteric language. The goal of this project was to contain some quirky or novel syntax in a stack-style program

null 0 Dec 24, 2021
Rust-verification-tools - RVT is a collection of tools/libraries to support both static and dynamic verification of Rust programs.

Rust verification tools This is a collection of tools/libraries to support both static and dynamic verification of Rust programs. We see static verifi

null 253 Dec 31, 2022
Rust bindings for libinjection

libinjection-rs Rust bindings for libinjection. How to use Add libinjection to dependencies of Cargo.toml: libinjection = "0.2" Import crate: extern c

ArvanCloud 35 Sep 24, 2022
A simple password manager written in Rust

ripasso A simple password manager written in Rust. The root crate ripasso is a library for accessing and decrypting passwords stored in pass format (G

Joakim Lundborg 548 Dec 26, 2022
tcp connection hijacker, rust rewrite of shijack

rshijack tcp connection hijacker, rust rewrite of shijack from 2001. This was written for TAMUctf 2018, brick house 100. The target was a telnet serve

null 377 Jan 1, 2023
A fast, simple, recursive content discovery tool written in Rust.

A simple, fast, recursive content discovery tool written in Rust ?? Releases ✨ Example Usage ✨ Contributing ✨ Documentation ?? ?? What the heck is a f

epi 3.6k Dec 30, 2022
link is a command and control framework written in rust

link link is a command and control framework written in rust. Currently in alpha. Table of Contents Introduction Features Feedback Build Process Ackno

null 427 Dec 24, 2022
CVEs for the Rust standard library

Rust CVE Preface This is a list of CVEs for unsound APIs in the Rust standard library. These bugs break Rust's memory safety guarantee and lead to sec

Yechan Bae 26 Dec 4, 2022
Rust bindings for VirusTotal/Yara

yara-rust Bindings for the Yara library from VirusTotal. More documentation can be found on the Yara's documentation. Example The implementation is in

null 43 Dec 17, 2022
Rust library for building and running BPF/eBPF modules

RedBPF A Rust eBPF toolchain. Overview The redbpf project is a collection of tools and libraries to build eBPF programs using Rust. It includes: redbp

foniod 1.5k Jan 1, 2023