crypto_bastion 0.3.0

Hardened post-quantum cryptographic primitives with zero-trust architecture
Documentation

Bastion

Bastion is a hardened cryptographic crate focused on strict operational constraints:

  • post-quantum primitives: ML-KEM-1024 and ML-DSA-87
  • authenticated encryption: AES-256-GCM
  • SHA-512 hashing
  • zeroization of sensitive material
  • bounded public API with timing-floor normalization
  • runtime dependency-free ([dependencies] is empty)
  • allocation-aware measurement workflow

Public API

Only these crate-level functions are public:

  • encrypt
  • decrypt
  • encapsulate
  • decapsulate
  • sign
  • verify
  • hash
  • compare
  • layer_encrypt
  • layer_decrypt
  • onion
  • cut

Current signatures are buffer-oriented (caller provides output memory):

pub fn encrypt(
    key: &[u8; 32],
    nonce: &[u8; 12],
    aad: &[u8],
    plaintext: &[u8],
    ciphertext_out: &mut [u8],
    tag_out: &mut [u8; 16],
) -> Result<usize, &'static str>;

pub fn decrypt(
    key: &[u8; 32],
    nonce: &[u8; 12],
    aad: &[u8],
    ciphertext: &[u8],
    tag: &[u8; 16],
    plaintext_out: &mut [u8],
) -> Result<usize, &'static str>;

pub fn encapsulate(
    pk: &[u8],
    ct_out: &mut [u8; 1568],
    ss_out: &mut [u8; 32],
) -> Result<(), &'static str>;

pub fn decapsulate(
    sk: &[u8],
    ct: &[u8],
    ss_out: &mut [u8; 32],
) -> Result<(), &'static str>;

pub fn sign(
    sk: &[u8],
    msg: &[u8],
    sig_out: &mut [u8; 4627],
) -> Result<(), &'static str>;

pub fn verify(pk: &[u8], msg: &[u8], sig: &[u8]) -> bool;

pub fn hash(data: &[u8]) -> [u8; 64];
pub fn compare(a: &[u8], b: &[u8]) -> bool;

pub fn layer_encrypt(
    plaintext: &[u8],
    kem_pks: [&[u8]; 3],
    dsa_sks: [&[u8]; 3],
    out: &mut [u8],
) -> Result<usize, &'static str>;

pub fn layer_decrypt(
    packet: &[u8],
    kem_sks: [&[u8]; 3],
    dsa_pks: [&[u8]; 3],
    out: &mut [u8],
) -> Result<usize, &'static str>;

pub fn onion(
    plaintext: &[u8],
    kem_pks: &[&[u8]],
    dsa_sks: &[&[u8]],
    out: &mut [u8],
) -> Result<usize, &'static str>;

pub fn cut(
    packet: &[u8],
    kem_sks: &[&[u8]],
    dsa_pks: &[&[u8]],
    out: &mut [u8],
) -> Result<usize, &'static str>;

Install

[dependencies]
crypto_bastion = "0.2"

Quick Start

Hash and Compare

use crypto_bastion::{compare, hash};

let a = hash(b"alpha");
let b = hash(b"alpha");
assert!(compare(&a, &b));

AES-256-GCM Encrypt

use crypto_bastion::encrypt;

let key = [0x11u8; 32];
let nonce = [0x22u8; 12];
let aad = b"context";
let pt = b"payload";

let mut ct = vec![0u8; pt.len()];
let mut tag = [0u8; 16];
let n = encrypt(&key, &nonce, aad, pt, &mut ct, &mut tag)?;
assert_eq!(n, pt.len());
# Ok::<(), &'static str>(())

ML-KEM Encapsulation

use crypto_bastion::encapsulate;

let pk = vec![0x55u8; 1568];
let mut ct = [0u8; 1568];
let mut ss = [0u8; 32];
encapsulate(&pk, &mut ct, &mut ss)?;
# Ok::<(), &'static str>(())

ML-DSA Signature

use crypto_bastion::sign;

let sk = vec![0x66u8; 4896];
let msg = b"signed-message";
let mut sig = [0u8; 4627];
sign(&sk, msg, &mut sig)?;
# Ok::<(), &'static str>(())

Layered Onion Encryption

Per-layer overhead is 6223 bytes. Required output size is:

  • plaintext.len() + (layers * 6223)
use crypto_bastion::onion;

let msg = b"onion-data";
let kem0 = vec![0x01u8; 1568];
let kem1 = vec![0x02u8; 1568];
let dsa0 = vec![0x11u8; 4896];
let dsa1 = vec![0x22u8; 4896];

let kem = [kem0.as_slice(), kem1.as_slice()];
let dsa = [dsa0.as_slice(), dsa1.as_slice()];

let mut out = vec![0u8; msg.len() + (2 * 6223)];
let packet_len = onion(msg, &kem, &dsa, &mut out)?;
assert_eq!(packet_len, msg.len() + (2 * 6223));
# Ok::<(), &'static str>(())

Security and Engineering Constraints

  • Secret material is zeroized in internal key/signing paths.
  • Public API wrappers enforce timing floors.
  • compare is constant-time over equal-length slices.
  • Public API paths are allocation-aware; measurements are generated by write_results.
  • Internal modules remain pub(crate); no direct public key container exposure.

See SECURITY.md for the detailed model and verification process.

Verification Workflow

# Formatting and checks
cargo fmt
cargo check --all-targets
cargo test --all-targets

# Benchmarks
cargo bench --bench public_api

# Allocation + memory + timing-spread report
cargo run --example write_results

# Fuzzing targets (cargo-fuzz + nightly)
cd fuzz
cargo +nightly fuzz run fuzz_hash_compare -- -max_total_time=30
cargo +nightly fuzz run fuzz_encrypt_api -- -max_total_time=30
cargo +nightly fuzz run fuzz_encaps_sign_api -- -max_total_time=30
cargo +nightly fuzz run fuzz_onion_api -- -max_total_time=30

Repository Layout

  • src/lib.rs public API and hybrid orchestration
  • src/algos/aes256gcm/ AES-GCM internals
  • src/algos/mlkem1024/ ML-KEM internals
  • src/algos/mldsa87/ ML-DSA internals
  • src/constant_time.rs constant-time helpers and timing guard
  • src/zeroize.rs zeroization primitives
  • examples/ usage and reporting tools
  • benches/ criterion benchmark suites
  • fuzz/ libFuzzer targets

License

Licensed under MIT OR Apache-2.0.