briny 0.1.0

Low-level foundational utilities for the briny ecosystem
Documentation
# briny


**Secure, zero-trust data validation and binary serialization for embedded and systems Rust.**

`briny` gives you airtight control over what data is trusted and when. It helps you securely parse, validate, and serialize binary-structured data without ever trusting unchecked input.

---

## What Makes Briny Different?


Briny enforces **Zero Trust Architecture (ZTA)** principles **at compile time**. Just like Rust’s ownership system prevents memory safety bugs **before runtime**, Briny prevents logic from touching untrusted or unvalidated input **before it compiles**. No hopeful parsing, no runtime footguns.

### If you follow Briny’s rules


- All external data must pass `Validate` before use
- All deserialized structures are wrapped in `TrustedData`
- No logic can access unchecked input without being explicit

### If you *don't* follow the rules


- It’s like misusing `unsafe {}`*you opt out of the safety net*
- Briny won’t stop you from writing broken or insecure `Validate` impls
- You can still violate trust boundaries *after* validation, if you ignore discipline
- Briny can't enforce runtime misuse beyond the type system.

---

## Why Use Briny?


- Enforce trust boundaries with marker traits (`Trusted`, `Untrusted`)
- Zero dependencies and `#![no_std]` compatible
- Built for embedded, security-critical, and sandboxed Rust systems
- Prevent bugs **before they ship**, **before they're tested**, **before they compile**

### Warning: Briny Is a Power Tool


Briny helps you build airtight validation infrastructure — but like `unsafe`, **it must be used with care**. If downstream crates implement `Validate` incorrectly, or mutate `TrustedData` unsafely, **no compile-time model can save you**.

Use Briny to make the safe path easy and the unsafe path obvious.

Briny is ideal for:

- Hardened OS modules
- Secure microservices
- Kernel/user-mode message passing
- Cryptographic protocols
- Embedded bootloaders and firmware parsing
- WASM interfaces

Use Briny where trust boundaries matter most — and test isn’t enough.

---

## Features


- Zero Trust Architecture (ZTA)–aligned
- Binary-safe serialization via `Pack`/`Unpack`
- Trusted vs. untrusted data split at the type level
- Fixed-size byte buffer abstraction (`ByteBuf<T, N>`)
- Dependency-free (no `std` or `alloc`)

### Trust Model


`briny` enforces explicit trust boundaries using:

- `UntrustedData<T>`: Marker for unsafe input (from users, network, disk, etc.)
- `Validate`: Trait that defines the rules for converting untrusted data into trusted form
- `TrustedData<T>`: Guarantees validation has occurred — only safe data gets in
- Sealed trait `Trusted` ensures trust cannot be forged outside the crate

This ZTA-style model improves security on many frontiers, meaning:

- No unchecked logic runs on untrusted data
- All transitions are explicit and type-checked
- You can’t forget to validate

---

## Example


```rust
use briny::prelude::*;

struct MyData([u8; 4]);

impl Validate for MyData {
    fn validate(&self) -> Result<(), ValidationError> {
        if self.0[0] == 42 { Ok(()) } else { Err(ValidationError) }
    }
}

impl Pack for MyData {
    fn pack(&self, mut out: PackRef<'_>) -> Result<(), ValidationError> {
        out.ref_mut().copy_from_slice(&self.0);
        Ok(())
    }
}

impl Unpack for MyData {
    fn unpack_and_validate(input: UnpackBuf<'_>) -> Result<TrustedData<'_, Self>, ValidationError> {
        let slice = input.as_slice();
        if slice.len() != 4 {
            return Err(ValidationError);
        }
        let data = MyData([slice[0], slice[1], slice[2], slice[3]]);
        TrustedData::new(data)
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // random bytes
    let external = UntrustedData::new([42, 0, 0, 0]);

    // validate the payload
    let my = MyData(external.into_inner());
    let trusted = TrustedData::new(my)?;

    // serialize it
    let mut buf = [0u8; 4];
    trusted.pack(PackRef::new(&mut buf))?;
    assert_eq!(buf, [42, 0, 0, 0]);
    
    Ok(())
}
```

## Comparison


| Feature | `serde` | `validator` | `nom` | `briny` |
|-----------------------------------|:-:|:-:|:-:|:-:|
| Compile-time security guarantees  | N | N | N | Y |
| Blocks parsing before validation  | N | N | N | Y |
| Validation enforced by compiler   | N | N | N | Y |
| Type-level trust separation       | N | N | N | Y |
| `no_std` compatible               | ~ | N | Y | Y |
| Accidental bypasses impossible    | N | N | N | Y |

### What Briny Does Not Do


While Briny enforces trust boundaries at compile time, it is *not* a one-size-fits-all validation framework. It does not:

- Parse or validate complex or nested data formats like JSON, XML, or YAML.
- Handle cryptographic operations or key management.
- Provide runtime-configurable validation rules or dynamic schema updates.
- Offer detailed validation error reporting with rich diagnostics.
- Support heap allocations or complex data structures requiring `std` or `alloc`.

Use Briny when you need **binary-safe, zero-cost, compile-time enforced trust** for fixed-layout, embedded, or low-level data structures.

For everything else—especially rich data formats or dynamic validation—consider combining Briny with crates like `serde`, `validator`, or `nom`.

Comparison use Case: Validate a 4-byte array, first byte must be 42

### serde — Deserialization without enforced validation


```rust
use serde::Deserialize;

#[derive(Deserialize)]

struct MyData([u8; 4]);

// Deserialize blindly, even if data is bad
let my: MyData = bincode::deserialize(&input_bytes)?;

// No guarantee this is safe!
assert_eq!(my.0[0], 42); // Could panic or be wrong
```

Risk: Data is used before it's validated. The deserialized value is implicitly trusted.

### validator — Runtime validation, trust still implicit


```rust
use validator::{Validate};

#[derive(Validate)]

struct MyData {
    #[validate(custom = "validate_first_byte")]
    data: [u8; 4],
}

fn validate_first_byte(data: &[u8; 4]) -> Result<(), validator::ValidationError> {
    if data[0] == 42 { Ok(()) } else { Err(ValidationError::new("bad")) }
}

// Data is deserialized before it's validated
let my: MyData = serde_json::from_str(json_input)?;
my.validate()?; // You must remember to call this!
```

Risk: You can forget to call .validate(), and the data was already used.

### nom — Binary parsing with separate validation


```rust
use nom::{bytes::complete::take, IResult};

fn parse(input: &[u8]) -> IResult<&[u8], [u8; 4]> {
    let (rest, bytes) = take(4usize)(input)?;
    Ok((rest, [bytes[0], bytes[1], bytes[2], bytes[3]]))
}

// Parse succeeds regardless of content
let (_, my_data) = parse(&input_bytes)?;
if my_data[0] != 42 {
    return Err("bad");
}
```

Risk: Parsing and validation are disconnected. It's easy to skip checks.

### briny — Enforced trust boundaries at the type level


```rust
use briny::prelude::*;

struct MyData([u8; 4]);

impl Validate for MyData {
    fn validate(&self) -> Result<(), ValidationError> {
        if self.0[0] == 42 { Ok(()) } else { Err(ValidationError) }
    }
}

impl Unpack for MyData {
    fn unpack_and_validate(input: UnpackBuf<'_>) -> Result<TrustedData<'_, Self>, ValidationError> {
        let slice = input.as_slice();
        if slice.len() != 4 { return Err(ValidationError); }
        TrustedData::new(MyData([slice[0], slice[1], slice[2], slice[3]]))
    }
}

// From raw input to trusted, validated value
let buf = UnpackBuf::new(&input_bytes);
let trusted: TrustedData<'_, MyData> = MyData::unpack_and_validate(buf)?;

// Cannot access trusted logic until valid
trusted.get(); // Fully safe
```

Guaranteed: Data must be validated before it compiles. No unsafe access is even possible without going through the Validate gate.

---

## Raw Bytes


Use `ByteBuf<T, N>` to handle fixed-size byte arrays before parsing:

```rust
use briny::prelude::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let input = ByteBuf::<u32, 4>::new(42u32.to_le_bytes());
    let _parsed = input.parse()?; // validated and parsed as u32
    Ok(())
}
```

This is useful when reading from sockets, files, or hardware registers.

### Prelude


Briny provides a prelude module for ergonomic imports:

```rust
use briny::prelude::*;
// brings in: Validate, TrustedData, UntrustedData, Pack, Unpack, etc.
```

## Install


Add to your `Cargo.toml`:

```toml
[dependencies]
briny = "0.1.0"
```

This crate is #![no_std], fully portable, and ideal for embedded and security-critical systems.

## Project Status


- [*] Security-first API design
- [*] 100% safe Rust (no unsafe)
- [*] Fully tested (integration and unit tests)
- [*] No dependencies
- [*] `#![no_std]` support
- [!] Community audits welcome

## Contributing


Contributions, bug reports, and suggestions are welcome! This project aims to help build verifiably secure foundations for low-level and embedded Rust development.

### License


`briny` is under an MIT license.