Skip to content

everanium/itb

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

273 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ITB
No beginning. No end. Ouroboros.
Designed to protect critical data from future superintelligence.

ITB — Information-Theoretic Barrier with Ambiguity-Based Security

What "information-theoretic barrier" means here. ITB's security rests on two architectural mechanisms that operate independently of computational hardness assumptions: (1) noise absorption — hash outputs are XOR'd into a random container generated by crypto/rand, so the attacker observes random bytes regardless of hash output; and (2) encoding ambiguity — the triple-seed structure (startSeed / dataSeed / noiseSeed) creates 7^P equally-valid configurations under CCA observations, growing exponentially with payload size. Above ~2.5 KB at 1024-bit keys, ambiguity exceeds the key space; at 64 KB approximately 2^26,414 configurations are simultaneously consistent with any single observation. PRF-grade hash and CSPRNG-quality random container are required assumptions; the construction degrades under their failure as documented in PROOFS.md.

Interlocked Mode (optional) engages a per-chunk PRF-keyed bit-permutation overlay: each 24-bit chunk of the plaintext payload is permuted under a fresh permutation derived from a chained PRF (before COBS framing), raising per-chunk enumeration cost to 2^33 balanced 8-of-24 partitions (Triple variant) or 2^64 distinct permutations on 24 bits (Single variant). The mode is opt-in and process-wide; ciphertext wire format is unchanged from the default mode. Hardens KPA-resistance way.

Security notice. ITB is an experimental symmetric cipher construction without prior peer review, independent cryptanalysis, or formal certification. The construction's security properties have not been verified by independent cryptographers or mathematicians.

The information-theoretic barrier is a software-level property based on computational behavior of hash functions and CSPRNG output, reinforced by two independent barrier mechanisms: noise absorption from CSPRNG, and encoding ambiguity (56^P without CCA, 7^P under CCA) from triple-seed isolation. Architectural layers deny the point of application: independent startSeed and 8-noisePos ambiguity from independent noiseSeed under Full KPA, plus gcd(7,8)=1 byte-splitting under Partial KPA. Full KPA defense is 3-factor under PRF assumption (4-factor under Partial KPA) — see Proof 4a. It provides no guarantees against hardware-level attacks including: power analysis (DPA/SPA), microarchitectural side-channels (Spectre, Meltdown, Rowhammer, cache timing), undiscovered side-channel leakages, or CSPRNG implementation weaknesses.

PRF-grade hash functions are required. No warranty is provided.

A parameterized symmetric cipher construction library for Go that makes hash output unobservable under passive observation through two independent barrier mechanisms: noise absorption (CSPRNG random container makes hash output unobservable) and encoding ambiguity (secret rotation creates 7^P unverifiable configurations surviving CCA). Triple-seed isolation ensures compromise of any domain provides zero information about the others.

Ambiguity-Based Security: uncertainty about the correct configuration grows exponentially with data size, inverting Shannon's classical relationship. Above ~1.2 KB (no CCA) or ~2.5 KB (CCA) for 1024-bit keys, encoding ambiguity exceeds the key space. At 64 KB: 2^26,414 equally valid configurations — no computational model can enumerate them.

How the barrier works — accessible explanation

Triple Ouroboros — 7-seed variant with 3× security

Why known-plaintext and advanced attacks do not break the barrier

Empirical red-team validation — 12 hash primitives (including CRC128 and FNV-1a lo-lane for positive control) × 2×2 configuration matrix (Single + Triple Ouroboros × BF=1 + BF=32). Multiple empirical phases — structural / FFT / Markov, per-pixel candidate distinguisher, startPixel enumeration, ChainHash SAT-cost analysis + hash-agnostic bias audit, Direct Crib KPA SAT-cost analysis, nonce-reuse demasker with 96-cell Partial KPA matrix, 1008-cell related-seed differential, rotation-invariant edge case — all PRF-grade primitives neutralized.

Discord: discord.gg/wRYF8shHpd - invite to chat with developer.

Scientific paper (Preprint) — A. Kuvshinov, "A Symmetric Cipher Construction with Ambiguity-Based Security"

Zero external dependencies beyond ABI contracts with standard PRF primitives (BLAKE2/3, ChaCha20, AES-CMAC, SipHash-2-4, Areion-SoEM); the chain-absorb hot path is hand-written ZMM AVX-512 ASM.

Why ITB: Inverted Approach to Cryptography

Traditional symmetric ciphers (AES, ChaCha20) place all security burden on the mathematical strength of their core primitive. The keystream is XOR'd directly with plaintext — any weakness in the primitive is immediately exploitable because the attacker observes the primitive's output.

ITB inverts this approach. Instead of relying solely on the primitive's strength, the construction interposes a random container (generated from crypto/rand) between the hash output and the observer. The hash output is consumed by modifying random bytes that the attacker never sees — the original container values are never transmitted. This creates an information-theoretic barrier: no computational power can extract information that does not exist in the observation.

Why the math is simple. The construction uses only elementary operations: XOR, bitwise AND, modulo, bit shifts. There are no Galois fields, no S-boxes, no polynomial multiplication. This is not a weakness — it is a consequence of the design. The security comes from the architecture (random container, triple-seed isolation, per-bit XOR, noise embedding), not from the complexity of the math. Each architectural layer addresses a specific attack vector:

  • Random container — hash output unobservable under passive observation (COA, KPA)
  • Per-bit XOR (1:1) — 56 independent mask bits per pixel, every observation consistent with any plaintext
  • Triple-seed isolation — CCA leaks only noiseSeed (3 bits/pixel, MAC + Reveal only); dataSeed and startSeed remain independent
  • Noise bit embedding — no bit position is deterministically data from the public format

Why triple-seed is necessary. Without three independent seeds, a leak in one domain cascades: CCA reveals noise positions → same seed gives rotation and XOR → full configuration recovered. Triple-seed isolation ensures each leak is contained: CCA → only noiseSeed, cache side-channel → only startSeed, dataSeed → zero software-observable exposure. This is the minimum configuration where every leak is architecturally isolated.

Why the Barrier and PRF are Complementary. In traditional ciphers, the attacker directly observes the primitive's output (keystream XOR plaintext). Any weakness in the primitive is immediately exploitable. In ITB, the hash output is absorbed by a random container modification — the attacker sees modified random bytes, not hash outputs. Under the random-container model, every observed byte value is compatible with every possible hash output. PRF required. PRF closes the candidate-verification step; barrier and architectural layers (triple-seed isolation, encoding ambiguity; plus byte-splitting under Partial KPA) deny the point of application — 3-factor combination under PRF assumption (4-factor under Partial KPA). Neither is sufficient alone: architectural layers cannot resist an invertible hash, and without the barrier the attacker observes the keystream directly (as in AES-CTR, ChaCha20), making any PRF weakness immediately exploitable. See Proof 4a.

Why quantum structural attacks are conjectured mitigated. Quantum algorithms like Simon (periodicity), BHT (collisions), and quantum differential/linear analysis require observable structural relations between inputs and outputs. The random container makes these relations unobservable — the attacker cannot build the algebraic structures that quantum algorithms exploit. Additionally, ITB's MAC oracle (when present) is inherently classical: it accepts concrete bytes over a network, not quantum superposition queries (Q2 model inapplicable). This is an architectural observation that has not been independently verified.

Important. ITB is an experimental construction without peer review or independent cryptanalysis. The information-theoretic barrier is a software-level property, reinforced by two independent barrier mechanisms: noise absorption from CSPRNG, and encoding ambiguity (56^P without CCA, 7^P under CCA) from triple-seed isolation. Architectural layers deny the point of application: independent startSeed and 8-noisePos ambiguity from independent noiseSeed under Full KPA, plus gcd(7,8)=1 byte-splitting under Partial KPA. Full KPA defense is 3-factor under PRF assumption (4-factor under Partial KPA) — see Proof 4a. It provides no guarantees against hardware-level attacks. All security claims are under the random-container model and have not been independently verified.

Installation

go get github.com/everanium/itb@latest

Building

ITB ships with two pixel-processing backends selected automatically at compile time:

Mode Command Pixel Processing Requirements
CGO (default) -buildmode=c-shared C with SIMD auto-vectorization C compiler (GCC/Clang) + AVX-512
No ITB ASM (CGO) -buildmode=c-shared -tags=noitbasm C with SIMD auto-vectorization, ITB chain-absorb / Lock Soup / Areion permutation ASM disabled — upstream stdlib ASM (zeebo/blake3, golang.org/x/crypto, jedisct1/go-aes) stays engaged C compiler (GCC/Clang)

On AVX-512 hosts, hand-written ZMM-batched chain-absorb ASM kernels accelerate the per-pixel hash hot path 2×-7× over the per-call -tags=noitbasm fallback across all nine PRF-grade primitives (Areion-SoEM-256/512, BLAKE2b-256/512, BLAKE2s, BLAKE3, AES-CMAC, SipHash-2-4, ChaCha20) — see BENCH.md / BENCH3.md for measured numbers on Intel Rocket Lake and AMD EPYC 9655P (Zen 5). CGO mode (default) layers a C per-pixel kernel on top of the hash dispatch; building with CGO_ENABLED=0 swaps that for a portable Go pixel pipeline while the Go-assembly ZMM chain-absorb hash kernels stay engaged when AVX-512 is present. Per-pixel kernel uses three runtime-dispatched tiers:

  • Tier A — AVX-512F + AVX-512BW + AVX-512VL + GFNI + AVX-512VBMI: 8-pixel ZMM batch. Phase 1 (extract 8×56 bits) fuses VPERMB + VPSRLQ + VPMULTISHIFTQB into 5 ZMM ops. Phase 4 (per-pixel rotate) and Phase 5 (per-pixel noise-bit insert) lower to single VGF2P8AFFINEQB ZMM ops. Insane Interlocked Mode (SetLockSoup(1)) on Single Ouroboros lowers its per-chunk bit-permutation to a native AVX-512 VBMI VPERMB + VPMOVM2B + VPTESTMB ASM kernel, with a Pure Go bit-shift gather fallback on hosts without AVX-512 VBMI. Active on Intel Rocket Lake / Tiger Lake / Sapphire Rapids+ and AMD Zen 4 / Zen 5.
  • Tier B — AVX2 + GFNI: 4-pixel YMM batch. Same five-phase shape, halved width. Phase 3-5 use VPXOR / VGF2P8AFFINEQB / VPAND / VPOR on YMM. Active on Intel Coffee Lake+ and AMD Zen 3+ (covers Alder Lake E-cores and similar AVX-512-disabled deployments). Insane Interlocked Mode (SetLockSoup(1)) lowers its per-chunk bit-permutation to a native BMI2 PEXTL/PDEPL ASM kernel, with a Pure Go fallback on hosts without BMI2.
  • Tier C — Fallback: 4-pixel batched scalar loop, same memory layout as Tier B with no SIMD intrinsics. Runs on every host GCC supports — IFUNC is not used, so macOS Mach-O and Windows COFF builds reach this path through the same runtime branch as Linux/FreeBSD ELF. ARM64 (NEON) intrinsics are not yet implemented and currently route through this tier; GCC -O3 still auto-vectorizes byte-parallel phases to NEON in a limited form.

CGO speedup also covers L1-cache-friendly micro-batching (512 pixels per C call), parallel noise/data hash computation through BatchHashFunc factories, sync.Pool for hash array reuse, and __builtin_prefetch 8 pixels ahead of the current iteration.

Platform Per-pixel kernel Areion-SoEM batched dispatch
amd64 + AVX-512+GFNI+VBMI (Intel Rocket Lake / Tiger Lake+, AMD Zen 4+) Tier A (ZMM, 8-pixel batch) AVX-512+VAES ASM, 4-lane batch + SoEM two-half ILP interleaving (internal/areionasm/areion_amd64.s)
amd64 + AVX2+GFNI (AMD Zen 3+, Coffee Lake+) Tier B (YMM, 4-pixel batch) AVX2+VAES ASM, 4-lane per-half permute (no SoEM ILP — AVX-512-only)
amd64 without VAES / older Tier C — Fallback Go fallback via aes.Round4HW
arm64 + ARM Crypto Extension (Graviton 2+, Apple M1+, Neoverse N1+/V1+/V2+) Tier C — Fallback ARM Crypto Extension AArch64 ASM, 4-lane parallel AESE/AESMC (internal/areionasm/areion_arm64.s)
other GCC targets (RISC-V, PowerPC, MIPS, …) Tier C — Fallback Go fallback via aes.Round4HW
CGO_ENABLED=0 Pure Go (process_generic.go) Go fallback

Hash computation remains in Go in both modes (pluggable hash functions); the C pixel kernel is platform-portable through __attribute__((target(...))) per-helper feature gates rather than IFUNC, so non-Linux/non-FreeBSD targets degrade gracefully.

Usage

# Build shared library
git clone https://github.com/everanium/itb && cd itb

# CGO backend (default)
cd cmd/cshared && go build -buildmode=c-shared -o ../../dist/linux-amd64/libitb.so .

# CGO backend (most portable, audit-grade deterministic)
cd cmd/cshared && go build -buildmode=c-shared -tags=noitbasm -o ../../dist/linux-amd64/libitb.so .

Tests

# CGO backend (default)
go test -timeout=3600s -race ./...

# CGO backend (most portable, audit-grade deterministic)
go test -tags=noitbasm -timeout=3600s -race ./...

# Pure Go
CGO_ENABLED=0 go test -timeout=3600s . ./easy ./hashes ./macs ./internal/...
CGO_ENABLED=0 go test -tags=noitbasm -timeout=3600s . ./easy ./hashes ./macs ./internal/...

Benchmarks

# CGO backend (default)
go test -bench='Benchmark*' -run='^$' -benchtime=5s -count=1 .

# CGO backend (most portable, audit-grade deterministic)
go test -tags=noitbasm -bench='Benchmark*' -run='^$' -benchtime=5s -count=1 .

# Pure Go backend
CGO_ENABLED=0 go test -bench='Benchmark*' -run='^$' -benchtime=5s -count=1 .
CGO_ENABLED=0 go test -tags=noitbasm -bench='Benchmark*' -run='^$' -benchtime=5s -count=1 .

Performance

Full benchmark results across all ITB key sizes (512, 1024, 2048 bit), hash functions, and CPUs: BENCH.md Triple Ouroboros benchmarks (7-seed, 3× security): BENCH3.md

Throughput scales with data size due to goroutine parallelism across CPU cores. CGO mode uses three runtime-dispatched per-pixel kernel tiers (AVX-512+GFNI+VBMI 8-pixel ZMM, AVX2+GFNI 4-pixel YMM, Tier C scalar) plus AVX-512 ZMM-batched chain-absorb hash kernels for every PRF-grade primitive (hashes/internal/<primitive>asm plus internal/areionasm for Areion-SoEM). CGO_ENABLED=0 alone swaps only the C pixel kernel for the portable Go pipeline; the ZMM-batched hash ASM and upstream stdlib ASM stay engaged via Go assembly, so end-to-end throughput stays close to the CGO default on AVX-512 hosts. The full scalar fallback is not usable with ITB (-tags=purego, where every upstream module honours the convention) is ~20×–100× slower when the ZMM hash kernels fall back to per-call scalar references — every primitive picks up a measurable ZMM uplift, but the relative gap is widest on the BLAKE / ARX primitives (heavier per-call closure overhead amortised across four lanes) and narrowest on AES-CMAC / SipHash-2-4, whose scalar paths already run AES-NI-accelerated through crypto/aes and the hand-tuned dchest/siphash assembly so the batched arm has less headroom to recover. The middle ground is -tags=noitbasm — disables the ITB chain-absorb wrapper while leaving upstream hash ASM engaged; throughput tracks the OLDBENCH single-Func numbers on hosts without AVX-512+VL where the 4-lane batched wrapper would be dead weight. Decrypt does not require crypto/rand and scales further on high-core-count CPUs.

ASIC Scalability

FPGA proof-of-concept is planned using open-source Verilog IP cores for SipHash and ChaCha20 DRBG, with a custom ITB pixel pipeline. Target: full encrypt/decrypt roundtrip on a single FPGA chip.

ITB's elementary operations (XOR, bitwise AND, modulo, bit shift, rotate) are trivial to implement in hardware. The construction's per-pixel parallelism (each pixel is independent) enables linear scalability through parallel processing units.

Pixel processing in ASIC:

  • All operations are combinational logic: XOR gates, barrel shifters, adders
  • No S-box ROM, no lookup tables, no GF(2^8) multiplier required
  • Each pixel can be processed by an independent hardware unit
  • 8 channels per pixel can be processed in parallel (8-wide datapath)
  • No DPA attack surface — register-only operations in silicon

Hash engine:

  • ARX-based PRF hash functions (SipHash-2-4/ChaCha20/BLAKE2s — chosen at design time) are pipeline-friendly in hardware: each individual operation (Add, Rotate, XOR) completes in 1 clock cycle; a full SipHash-2-4 call requires ~24 cycles for 20-byte input
  • Multiple hash engines can run in parallel (one per pixel pipeline)
  • No S-box in silicon — no DPA attack surface at the hardware level

Primary engineering challenge — PRNG throughput:

  • Container generation (crypto/rand) is the throughput bottleneck in software (~735 MB/s on modern CPUs)
  • In ASIC, a custom ChaCha20-based DRBG (ARX, DPA-free) seeded from a certified TRNG IP core generates random container fill, not cryptographic keys
  • Seeds (triple-seed) are external pre-shared inputs, not generated by the DRBG — they are loaded into ASIC secure registers via external key exchange
  • A single ChaCha20 DRBG core at ~4 GB/s may be sufficient — the pixel processing pipeline (2 hash calls per pixel) becomes the bottleneck before DRBG does
  • Scaling is achieved by adding parallel pixel pipelines, not additional DRBG cores
  • Decrypt does not require PRNG (no container generation) — decrypt throughput is limited only by hash engine and memory bandwidth

DPA-free full stack:

  • TRNG (certified IP core) → ChaCha20 DRBG streaming (custom, ARX) → ARX hash engine (SipHash-2-4/ChaCha20/BLAKE2s) → pixel processing (XOR, shift, rotate) — zero table lookups from PRNG to output, no DPA attack surface at any level

Theoretical throughput:

  • With ChaCha20 DRBG + parallel hash engines + parallel pixel processing, ASIC implementations could theoretically achieve >1-2 GB/s for both encrypt and decrypt — the problem is purely engineering, not architectural
  • Decrypt throughput could exceed encrypt due to absence of PRNG overhead

Concurrency

A single easy.Encryptor is NOT safe for concurrent use from multiple goroutines — cipher methods (Encrypt / Decrypt / EncryptAuth / DecryptAuth), per-instance setters, and Close / Import all mutate per-instance state without locking. Sharing one Encryptor across goroutines requires external synchronisation; distinct Encryptor values, each owned by one goroutine, run independently against the libitb worker pool.

By contrast, the low-level cipher free functions (itb.Encrypt128 / itb.Decrypt128 / itb.EncryptAuthenticated128 / itb.DecryptAuthenticated128 and Cfg variants plus the 256 / 512 width counterparts) take read-only Seed pointers and allocate output per call — they are thread-safe under concurrent invocation on the same seeds. The exception is the shared *itb.Config: concurrent setter mutations on a Config that other goroutines are reading must be serialised by the caller.

Caveat — Process-wide itb.Set* setters (SetNonceBits / SetBarrierFill / SetMaxWorkers / SetBitSoup / SetLockSoup) are atomic and safe to call from any goroutine. Atomic, but not logically race-free. Each setter performs a single atomic.Int32.Store, so concurrent setter calls race-free by themselves; but mutating any of these knobs while an encrypt or decrypt call is in flight corrupts the running operation. The cipher snapshots its configuration at call entry and a mid-flight change breaks the running invariants — same plaintext shipped through two halves of the call under different settings will not round-trip on the receiver. Treat the global knobs as set-once-at-startup; rare runtime updates need external sequencing against active cipher calls.

Streaming AEAD

Streaming AEAD authenticates a chunked stream end-to-end while preserving the deniability of the per-chunk MAC-Inside-Encrypt container. Each chunk's MAC binds the encrypted payload to a 32-byte CSPRNG stream anchor (written as a once-per-stream wire prefix), the cumulative pixel offset of preceding chunks, and a final-flag bit — defending against chunk reorder, replay within or across streams sharing the PRF / MAC key, silent mid-stream drop, and truncate-tail. The wire format adds 32 bytes of stream prefix plus one byte of encrypted trailing flag per chunk; no externally visible MAC tag.

All four examples below encrypt a 64 MiB random source file in 16 MiB chunks and verify sha256 round-trip on the decrypted output. The Easy paths drive the cipher through easy.Encryptor (per-instance configuration snapshot, internal MAC key allocation); the Low-Level paths drive the same cipher through the top-level free functions itb.EncryptStream / itb.EncryptStreamAuth and decrypt counterparts (process-wide configuration via itb.Set*, explicit seed + MAC handles).

Streaming Bindings Asymmetry

The Go core and the easy package expose io.Reader / io.Writer entry points for both the Streaming AEAD path and the plain (No-MAC) stream path. The official language bindings (Ada, C, C++, C#, D, Fortran, Rust, Node.js, Python and other bindings) expose IO-driven helpers for the Streaming AEAD path only; their plain-stream surface is a per-chunk free-function call with the caller driving the read/write loop. The two patterns produce identical on-wire bytes — the Alternative examples in the No-MAC subsections below mirror the binding-side idiom for callers who prefer external control over chunk granularity and back-pressure.

Streaming AEAD Easy (MAC Authenticated)

The high-level easy.Encryptor.EncryptStreamAuthIO consumes an io.Reader plus an explicit chunk size, generates the 32-byte stream_id prefix internally, drains the reader in chunkSize-byte windows, and writes each on-wire chunk to the supplied io.Writer in stream order. The matching DecryptStreamAuthIO reads the prefix, walks the wire bytes one chunk at a time, and writes recovered plaintext to the output writer. The MAC key is allocated CSPRNG-fresh inside the encryptor at construction time and is not exposed to the caller.

package main

import (
    "bufio"
    "os"

    "github.com/everanium/itb"
    "github.com/everanium/itb/easy"
)

const (
    srcPath   = "/tmp/64mb.src"
    encPath   = "/tmp/64mb.enc"
    dstPath   = "/tmp/64mb.dst"
    chunkSize = 16 * 1024 * 1024
)

func main() {
    itb.SetMaxWorkers(8)             // process-wide: limit to 8 CPU cores

    enc := easy.New("areion512", 1024, "hmac-blake3")
    defer enc.Close()
    enc.SetNonceBits(512)            // 512-bit nonce
    enc.SetBarrierFill(4)            // CSPRNG fill margin
    enc.SetBitSoup(1)                // bit-level split
    enc.SetLockSoup(1)               // Insane Interlocked Mode

    {
        fin, _ := os.Open(srcPath)
        fout, _ := os.Create(encPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        if err := enc.EncryptStreamAuthIO(br, bw, chunkSize); err != nil {
            panic(err)
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
    {
        fin, _ := os.Open(encPath)
        fout, _ := os.Create(dstPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        if err := enc.DecryptStreamAuthIO(br, bw); err != nil {
            panic(err)
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
}

Output:

Easy Mode src sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
Easy Mode dst sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
[OK] Easy Mode: 64 MiB roundtrip via stream-auth verified

Streaming AEAD Low-Level (MAC Authenticated)

Top-level free functions itb.EncryptStreamAuth / itb.DecryptStreamAuth take three explicit *Seed{N} handles plus a MACFunc closure built from the macs/ factory and stream through the same chunked-AEAD construction directly over io.Reader / io.Writer. The seeds are constructed via itb.NewSeed512 paired with the matching hash factory from the hashes/ registry; the MAC closure is built from a 32-byte CSPRNG key plus macs.Make("hmac-blake3", key). Process-wide setters configure the cipher; no per-instance Config snapshot exists at the low-level surface.

package main

import (
    "bufio"
    "crypto/rand"
    "os"

    "github.com/everanium/itb"
    "github.com/everanium/itb/hashes"
    "github.com/everanium/itb/macs"
)

const (
    srcPath   = "/tmp/64mb.src"
    encPath   = "/tmp/64mb.enc"
    dstPath   = "/tmp/64mb.dst"
    chunkSize = 16 * 1024 * 1024
)

func main() {
    itb.SetMaxWorkers(8)             // process-wide: limit to 8 CPU cores
    itb.SetNonceBits(512)
    itb.SetBarrierFill(4)
    itb.SetBitSoup(1)
    itb.SetLockSoup(1)

    hashFn, _, _ := hashes.Make512("areion512")
    noise, _ := itb.NewSeed512(1024, hashFn)
    data,  _ := itb.NewSeed512(1024, hashFn)
    start, _ := itb.NewSeed512(1024, hashFn)

    macKey := make([]byte, 32)
    rand.Read(macKey)
    macFunc, err := macs.Make("hmac-blake3", macKey)
    if err != nil { panic(err) }

    {
        fin, _ := os.Open(srcPath)
        fout, _ := os.Create(encPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        if err := itb.EncryptStreamAuth(noise, data, start, br, bw, macFunc, chunkSize); err != nil {
            panic(err)
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
    {
        fin, _ := os.Open(encPath)
        fout, _ := os.Create(dstPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        if err := itb.DecryptStreamAuth(noise, data, start, br, bw, macFunc); err != nil {
            panic(err)
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
}

Output:

Low-Level src sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
Low-Level dst sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
[OK] Low-Level Mode: 64 MiB roundtrip via stream-auth verified

Streaming Easy (No MAC)

The plain (non-authenticated) cipher path through easy.Encryptor. EncryptStreamIO walks the reader in chunkSize-byte windows and emits each ITB wire chunk verbatim; DecryptStreamIO recovers chunk extents from the on-wire W / H header per chunk, so no length prefix is needed at the application layer. No stream_id prefix and no per-chunk MAC tag — wrong- seed input produces random-looking plaintext rather than an error, and truncate-tail / reorder are not detected.

package main

import (
    "bufio"
    "os"

    "github.com/everanium/itb"
    "github.com/everanium/itb/easy"
)

const encPlainPath = "/tmp/64mb_plain.enc"
const dstPlainPath = "/tmp/64mb_plain.dst"

func main() {
    itb.SetMaxWorkers(8)             // process-wide: limit to 8 CPU cores

    enc := easy.New("areion512", 1024)
    defer enc.Close()
    enc.SetNonceBits(512)
    enc.SetBarrierFill(4)
    enc.SetBitSoup(1)
    enc.SetLockSoup(1)

    {
        fin, _ := os.Open(srcPath)
        fout, _ := os.Create(encPlainPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        if err := enc.EncryptStreamIO(br, bw, chunkSize); err != nil {
            panic(err)
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
    {
        fin, _ := os.Open(encPlainPath)
        fout, _ := os.Create(dstPlainPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        if err := enc.DecryptStreamIO(br, bw); err != nil {
            panic(err)
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
}

Output:

Easy Mode plain src sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
Easy Mode plain dst sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
[OK] Easy Mode plain stream: 64 MiB roundtrip verified

Alternative — user-driven loop (No memory residency):

The same easy.Encryptor exposes per-chunk Encrypt / Decrypt methods. Driving the read / write loop in caller code mirrors the per-chunk shape exposed by the official language bindings — useful when the caller wants explicit control over chunk granularity, back-pressure, or interleaved work between chunks. The on-wire bytes are wire-format-compatible with the IO method's output above: each on-wire chunk's own W / H header carries its length, so the decrypter walks the stream by reading enc.HeaderSize() bytes, calling enc.ParseChunkLen to learn the chunk's total wire length, then reading the body — no application-level length prefix required.

package main

import (
    "bufio"
    "io"
    "os"

    "github.com/everanium/itb"
    "github.com/everanium/itb/easy"
)

const encPlainPath = "/tmp/64mb_plain.enc"
const dstPlainPath = "/tmp/64mb_plain.dst"

func main() {
    itb.SetMaxWorkers(8)             // process-wide: limit to 8 CPU cores

    enc := easy.New("areion512", 1024)
    defer enc.Close()
    enc.SetNonceBits(512)
    enc.SetBarrierFill(4)
    enc.SetBitSoup(1)
    enc.SetLockSoup(1)

    {
        fin, _ := os.Open(srcPath)
        fout, _ := os.Create(encPlainPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        buf := make([]byte, chunkSize)
        for {
            n, rerr := io.ReadFull(br, buf)
            if rerr == io.EOF { break }
            if rerr != nil && rerr != io.ErrUnexpectedEOF { panic(rerr) }
            ct, err := enc.Encrypt(buf[:n])
            if err != nil { panic(err) }
            bw.Write(ct)
            if rerr == io.ErrUnexpectedEOF { break }
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
    {
        fin, _ := os.Open(encPlainPath)
        fout, _ := os.Create(dstPlainPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        header := make([]byte, enc.HeaderSize())
        for {
            _, rerr := io.ReadFull(br, header)
            if rerr == io.EOF { break }
            if rerr != nil { panic(rerr) }
            chunkLen, err := enc.ParseChunkLen(header)
            if err != nil { panic(err) }
            body := make([]byte, chunkLen-len(header))
            io.ReadFull(br, body)
            chunk := append(append(make([]byte, 0, chunkLen), header...), body...)
            pt, err := enc.Decrypt(chunk)
            if err != nil { panic(err) }
            bw.Write(pt)
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
}

Output:

Easy Mode plain user-loop src sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
Easy Mode plain user-loop dst sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
[OK] Easy Mode plain user-loop: 64 MiB roundtrip verified

Streaming Low-Level (No MAC)

Top-level free functions itb.EncryptStream / itb.DecryptStream take three explicit *Seed{N} handles (no MAC argument) and stream through the plain-Single-Ouroboros chunk pipeline directly over io.Reader / io.Writer. On-wire format = standard ITB chunk concatenation with no stream_id prefix and no per-chunk MAC tag.

package main

import (
    "bufio"
    "os"

    "github.com/everanium/itb"
    "github.com/everanium/itb/hashes"
)

const encPlainPath = "/tmp/64mb_plain.enc"
const dstPlainPath = "/tmp/64mb_plain.dst"

func main() {
    itb.SetMaxWorkers(8)             // process-wide: limit to 8 CPU cores
    itb.SetNonceBits(512)
    itb.SetBarrierFill(4)
    itb.SetBitSoup(1)
    itb.SetLockSoup(1)

    hashFn, _, _ := hashes.Make512("areion512")
    noise, _ := itb.NewSeed512(1024, hashFn)
    data,  _ := itb.NewSeed512(1024, hashFn)
    start, _ := itb.NewSeed512(1024, hashFn)

    {
        fin, _ := os.Open(srcPath)
        fout, _ := os.Create(encPlainPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        if err := itb.EncryptStream(noise, data, start, br, bw, chunkSize); err != nil {
            panic(err)
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
    {
        fin, _ := os.Open(encPlainPath)
        fout, _ := os.Create(dstPlainPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        if err := itb.DecryptStream(noise, data, start, br, bw); err != nil {
            panic(err)
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
}

Output:

Low-Level plain src sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
Low-Level plain dst sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
[OK] Low-Level Mode plain stream: 64 MiB roundtrip verified

Alternative — user-driven loop (No memory residency):

The Go-core width-less itb.Encrypt / itb.Decrypt helpers operate on a single chunk at a time. Driving the read / write loop in caller code mirrors the per-chunk shape exposed by the official language bindings' no-MAC plain-stream surface — useful when the caller wants explicit control over chunk granularity, back-pressure, or interleaved work between chunks. Each chunk's wire bytes are framed with a 4-byte big-endian length prefix (binding-style framing) so the decrypter can read one chunk's worth of bytes into a fresh buffer per iteration without parsing the on-wire ITB header.

package main

import (
    "bufio"
    "io"
    "os"

    "github.com/everanium/itb"
    "github.com/everanium/itb/hashes"
)

const encPlainPath = "/tmp/64mb_plain.enc"
const dstPlainPath = "/tmp/64mb_plain.dst"

func main() {
    itb.SetMaxWorkers(8)             // process-wide: limit to 8 CPU cores
    itb.SetNonceBits(512)
    itb.SetBarrierFill(4)
    itb.SetBitSoup(1)
    itb.SetLockSoup(1)

    hashFn, _, _ := hashes.Make512("areion512")
    noise, _ := itb.NewSeed512(1024, hashFn)
    data,  _ := itb.NewSeed512(1024, hashFn)
    start, _ := itb.NewSeed512(1024, hashFn)

    {
        fin, _ := os.Open(srcPath)
        fout, _ := os.Create(encPlainPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        buf := make([]byte, chunkSize)
        var lenBuf [4]byte
        for {
            n, rerr := io.ReadFull(br, buf)
            if rerr == io.EOF { break }
            if rerr != nil && rerr != io.ErrUnexpectedEOF { panic(rerr) }
            ct, err := itb.Encrypt(noise, data, start, buf[:n])
            if err != nil { panic(err) }
            lenBuf[0] = byte(len(ct) >> 24)
            lenBuf[1] = byte(len(ct) >> 16)
            lenBuf[2] = byte(len(ct) >> 8)
            lenBuf[3] = byte(len(ct))
            bw.Write(lenBuf[:])
            bw.Write(ct)
            if rerr == io.ErrUnexpectedEOF { break }
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
    {
        fin, _ := os.Open(encPlainPath)
        fout, _ := os.Create(dstPlainPath)
        br, bw := bufio.NewReader(fin), bufio.NewWriter(fout)
        var lenBuf [4]byte
        for {
            _, rerr := io.ReadFull(br, lenBuf[:])
            if rerr == io.EOF { break }
            if rerr != nil { panic(rerr) }
            chunkLen := int(lenBuf[0])<<24 | int(lenBuf[1])<<16 | int(lenBuf[2])<<8 | int(lenBuf[3])
            ct := make([]byte, chunkLen)
            io.ReadFull(br, ct)
            pt, err := itb.Decrypt(noise, data, start, ct)
            if err != nil { panic(err) }
            bw.Write(pt)
        }
        bw.Flush(); fin.Close(); fout.Close()
    }
}

Output:

Low-Level plain user-loop src sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
Low-Level plain user-loop dst sha256: c33ebd485683f8201518112418d2bd428d1fcc3e9e4da2f49eebd3cf3da8fd11
[OK] Low-Level Mode plain user-loop: 64 MiB roundtrip verified

Quick Start

Three configurations covering the most common usage patterns. Every key and every seed component is CSPRNG-generated; no master key, no key-derivation step. Cross-process persistence (encrypt today, decrypt tomorrow / on a different host) is documented in hashes/README.md and macs/README.md.

Easy: Areion-SoEM-512 (No MAC)

The high-level easy.Encryptor replaces the seven-line setup ceremony of the lower-level path with one constructor call. The encryptor allocates its own three (Single) or seven (Triple) seeds + MAC closure, snapshots the global configuration into a per-instance *itb.Config, and exposes setters that mutate only its own state without touching the process-wide itb.Set* accessors. Two encryptors with different settings can run concurrently without cross-contamination.

// Sender

package main

import (
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/easy"
)

func main() {
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

    // Single-Ouroboros (3 seeds) constructor — variadic args by type:
    // string matching hashes.Registry → primitive, string matching
    // macs.Registry → MAC, int → key_bits. Defaults: "areion512" /
    // 1024 / "hmac-blake3". Triple Ouroboros (7 seeds) → easy.New3(...).
    enc := easy.New("areion512", 2048, "hmac-blake3")
    defer enc.Close()

    // Per-instance configuration — mutates only this encryptor's
    // *itb.Config snapshot. Two encryptors built side-by-side carry
    // independent settings; process-wide itb.Set* accessors are NOT
    // consulted after construction.
    enc.SetNonceBits(512)   // 512-bit nonce (default: 128-bit)
    enc.SetBarrierFill(4)   // CSPRNG fill margin (default: 1, valid: 1, 2, 4, 8, 16, 32)
    enc.SetBitSoup(1)       // optional bit-level split ("bit-soup"; default: 0 = byte-level)
                            // auto-enabled for Single Ouroboros if SetLockSoup(1) is on
    enc.SetLockSoup(1)      // optional Insane Interlocked Mode: per-chunk PRF-keyed
                            // bit-permutation overlay on top of bit-soup;
                            // auto-enabled for Single Ouroboros if SetBitSoup(1) is on

    //enc.SetLockSeed(1)    // optional dedicated lockSeed for the bit-permutation
                            // derivation channel — separates that PRF's keying material
                            // from the noiseSeed-driven noise-injection channel; auto-
                            // couples SetLockSoup(1) + SetBitSoup(1). Adds one extra
                            // seed slot (3 → 4 for Single, 7 → 8 for Triple). Must be
                            // called BEFORE the first Encrypt — switching mid-session
                            // panics with easy.ErrLockSeedAfterEncrypt.

    // For cross-process persistence: enc.Export() returns a single
    // JSON blob carrying PRF keys, seed components, MAC key, and
    // (when active) the dedicated lockSeed material. Ship it
    // alongside the ciphertext or out-of-band.
    blob := enc.Export()
    fmt.Printf("state blob: %d bytes\n", len(blob))
    fmt.Printf("primitive: %s, key_bits: %d, mode: %d, mac: %s\n",
        enc.Primitive, enc.KeyBits, enc.Mode, enc.MACName)

    plaintext := []byte("any text or binary data - including 0x00 bytes")
    //chunkSize := 4 * 1024 * 1024 // 4 MB - bulk local crypto, not small-frame network streaming

    // One-shot encrypt into RGBWYOPA container.
    encrypted, err := enc.Encrypt(plaintext)
    if err != nil {
        panic(err)
    }
    //var ciphertext []byte
    //err := enc.EncryptStream(plaintext, func(chunk []byte) error {
    //    ciphertext = append(ciphertext, chunk...)
    //    return nil
    //})
    fmt.Printf("encrypted: %d bytes\n", len(encrypted))

    // Send encrypted payload + state blob
}

// Receiver

package main

import (
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/easy"
)

func main() {
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

    // Receive encrypted payload + state blob
    // var encrypted, blob []byte = ..., ...

    // Optional: peek at the blob's metadata before constructing a
    // matching encryptor. Useful when the receiver multiplexes blobs
    // of different shapes (different primitive / mode / MAC choices).
    prim, keyBits, mode, mac := easy.PeekConfig(blob)
    fmt.Printf("peek: primitive=%s, key_bits=%d, mode=%d, mac=%s\n",
        prim, keyBits, mode, mac)

    var dec *easy.Encryptor
    if mode == 1 {
        dec = easy.New(prim, keyBits, mac)
    } else {
        dec = easy.New3(prim, keyBits, mac)
    }
    defer dec.Close()

    // dec.Import(blob) below automatically restores the full
    // per-instance configuration (NonceBits, BarrierFill, BitSoup,
    // LockSoup, and the dedicated lockSeed material when sender's
    // SetLockSeed(1) was active). The Set* lines below are kept for
    // documentation — they show the knobs available for explicit
    // pre-Import override. BarrierFill is asymmetric: a receiver-set
    // value > 1 takes priority over the blob's barrier_fill (the
    // receiver's heavier CSPRNG margin is preserved across Import).
    dec.SetNonceBits(512)
    dec.SetBarrierFill(4)
    dec.SetBitSoup(1)
    dec.SetLockSoup(1)
    //dec.SetLockSeed(1)    // optional — Import below restores the dedicated
                            // lockSeed slot from the blob's lock_seed:true.

    // Restore PRF keys, seed components, MAC key, and the per-instance
    // configuration overrides (nonce_bits / barrier_fill / bit_soup /
    // lock_soup / lock_seed) from the saved blob.
    if err := dec.Import(blob); err != nil {
        panic(err)
    }

    // One-shot decrypt from RGBWYOPA container.
    decrypted, err := dec.Decrypt(encrypted)
    if err != nil {
        panic(err)
    }
    //var decrypted []byte
    //err = dec.DecryptStream(ciphertext, func(chunk []byte) error {
    //    decrypted = append(decrypted, chunk...)
    //    return nil
    //})
    fmt.Printf("decrypted: %s\n", string(decrypted))
}

Easy: Areion-SoEM-512 + HMAC-BLAKE3 (MAC Authenticated)

The MAC primitive is bound at construction time — the third positional argument selects one of the registry names (kmac256, hmac-sha256, hmac-blake3). The encryptor allocates a fresh 32-byte CSPRNG MAC key alongside the per-seed PRF keys; Export() carries all of them in a single JSON blob.

// Sender

package main

import (
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/easy"
)

func main() {
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

    enc := easy.New("areion512", 2048, "hmac-blake3")
    defer enc.Close()

    enc.SetNonceBits(512)
    enc.SetBarrierFill(4)
    enc.SetBitSoup(1)
    enc.SetLockSoup(1)

    //enc.SetLockSeed(1)    // optional dedicated lockSeed for the bit-permutation
                            // derivation channel — auto-couples SetLockSoup(1) +
                            // SetBitSoup(1). Adds one extra seed slot. Must be
                            // called BEFORE the first EncryptAuth.

    // Persistence blob — carries seeds + PRF keys + MAC key (and
    // the dedicated lockSeed material when SetLockSeed(1) is active).
    blob := enc.Export()
    fmt.Printf("state blob: %d bytes\n", len(blob))

    plaintext := []byte("any text or binary data - including 0x00 bytes")

    // Authenticated encrypt — 32-byte tag is computed across the
    // entire decrypted capacity and embedded inside the RGBWYOPA
    // container, preserving oracle-free deniability.
    encrypted, err := enc.EncryptAuth(plaintext)
    if err != nil {
        panic(err)
    }
    fmt.Printf("encrypted: %d bytes\n", len(encrypted))

    // Send encrypted payload + state blob
}

// Receiver

package main

import (
    "errors"
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/easy"
)

func main() {
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

    // Receive encrypted payload + state blob
    // var encrypted, blob []byte = ..., ...

    prim, keyBits, mode, mac := easy.PeekConfig(blob)

    var dec *easy.Encryptor
    if mode == 1 {
        dec = easy.New(prim, keyBits, mac)
    } else {
        dec = easy.New3(prim, keyBits, mac)
    }
    defer dec.Close()

    // dec.Import(blob) below automatically restores the full
    // per-instance configuration (NonceBits, BarrierFill, BitSoup,
    // LockSoup, and the dedicated lockSeed material when sender's
    // SetLockSeed(1) was active). The Set* lines below are kept for
    // documentation — they show the knobs available for explicit
    // pre-Import override. BarrierFill is asymmetric: a receiver-set
    // value > 1 takes priority over the blob's barrier_fill (the
    // receiver's heavier CSPRNG margin is preserved across Import).
    dec.SetNonceBits(512)
    dec.SetBarrierFill(4)
    dec.SetBitSoup(1)
    dec.SetLockSoup(1)
    //dec.SetLockSeed(1)    // optional — Import below restores the dedicated
                            // lockSeed slot from the blob's lock_seed:true.

    if err := dec.Import(blob); err != nil {
        panic(err)
    }

    // Authenticated decrypt — any single-bit tamper triggers MAC
    // failure (no oracle leak about which byte was tampered).
    decrypted, err := dec.DecryptAuth(encrypted)
    if err != nil {
        if errors.Is(err, easy.ErrClosed) {
            panic("encryptor was closed")
        }
        // The underlying itb.DecryptAuthenticated* returns a fixed-text
        // error on MAC verification failure; check the error string or
        // use the structural difference between MAC failure and other
        // decrypt errors.
        panic(err)
    }
    fmt.Printf("decrypted: %s\n", string(decrypted))
}

Easy: BLAKE2b-512 + HMAC-BLAKE3 (MAC Authenticated, 2048-bit Seeds)

Same flow as the previous example, swapping the primitive name ("blake2b512") and the MAC name ("hmac-blake3") at construction time. Mixing primitives at the encryptor level is one constructor argument away — no per-call PRF / batched-arm wiring.

// Sender

package main

import (
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/easy"
)

func main() {
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

    enc := easy.New("blake2b512", 2048, "hmac-blake3")
    defer enc.Close()

    enc.SetNonceBits(512)
    enc.SetBarrierFill(4)
    enc.SetBitSoup(1)
    enc.SetLockSoup(1)

    //enc.SetLockSeed(1)    // optional dedicated lockSeed; auto-couples LockSoup +
                            // BitSoup. Adds one extra seed slot. Must be called
                            // BEFORE the first EncryptAuth.

    blob := enc.Export()
    fmt.Printf("state blob: %d bytes\n", len(blob))

    plaintext := []byte("any text or binary data - including 0x00 bytes")
    encrypted, err := enc.EncryptAuth(plaintext)
    if err != nil {
        panic(err)
    }
    fmt.Printf("encrypted: %d bytes\n", len(encrypted))

    // Send encrypted payload + state blob
}

// Receiver

package main

import (
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/easy"
)

func main() {
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

    // Receive encrypted payload + state blob
    // var encrypted, blob []byte = ..., ...

    prim, keyBits, mode, mac := easy.PeekConfig(blob)

    var dec *easy.Encryptor
    if mode == 1 {
        dec = easy.New(prim, keyBits, mac)
    } else {
        dec = easy.New3(prim, keyBits, mac)
    }
    defer dec.Close()

    // dec.Import(blob) below automatically restores the full
    // per-instance configuration (NonceBits, BarrierFill, BitSoup,
    // LockSoup, and the dedicated lockSeed material when sender's
    // SetLockSeed(1) was active). The Set* lines below are kept for
    // documentation — they show the knobs available for explicit
    // pre-Import override. BarrierFill is asymmetric: a receiver-set
    // value > 1 takes priority over the blob's barrier_fill (the
    // receiver's heavier CSPRNG margin is preserved across Import).
    dec.SetNonceBits(512)
    dec.SetBarrierFill(4)
    dec.SetBitSoup(1)
    dec.SetLockSoup(1)
    //dec.SetLockSeed(1)    // optional — Import below restores the dedicated
                            // lockSeed slot from the blob's lock_seed:true.

    if err := dec.Import(blob); err != nil {
        panic(err)
    }

    decrypted, err := dec.DecryptAuth(encrypted)
    if err != nil {
        panic(err)
    }
    fmt.Printf("decrypted: %s\n", string(decrypted))
}

Easy: Mixed primitives — different PRF per seed slot

easy.NewMixed and easy.NewMixed3 accept a per-slot primitive spec, allowing the noise / data / start (and optional dedicated lockSeed) seed slots to use different PRF primitives within the same native hash width. The mix-and-match-PRF freedom of the lower-level path, surfaced through Easy Mode without forcing the caller off the high-level constructor. The state blob carries per-slot primitives + per-slot PRF keys; the receiver constructs a matching encryptor with the same spec and calls Import to restore.

// Sender

package main

import (
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/easy"
)

func main() {
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

    // Per-slot primitive selection (Single Ouroboros, 3 + 1 slots).
    // Every name must share the same native hash width — mixing
    // widths is rejected at construction with easy.ErrEasyMixedWidth.
    // Triple Ouroboros mirror — easy.NewMixed3(easy.MixedSpec3{...})
    // takes seven per-slot names (noise + 3 data + 3 start) plus
    // the optional PrimitiveL lockSeed.
    enc := easy.NewMixed(easy.MixedSpec{
        PrimitiveN: "blake3",      // noiseSeed:  BLAKE3
        PrimitiveD: "blake2s",     // dataSeed:   BLAKE2s
        PrimitiveS: "areion256",   // startSeed:  Areion-SoEM-256
        PrimitiveL: "blake2b256",  // dedicated lockSeed (optional;
                                   //   empty = no lockSeed slot)
        KeyBits:    1024,
        MACName:    "hmac-blake3",
    })
    defer enc.Close()

    // Per-instance configuration applies as for easy.New.
    enc.SetNonceBits(512)
    enc.SetBarrierFill(4)
    // BitSoup + LockSoup are auto-coupled on the on-direction by
    // PrimitiveL above; explicit calls below are unnecessary but
    // harmless if added.
    //enc.SetBitSoup(1)
    //enc.SetLockSoup(1)

    // Per-slot introspection — Primitive returns the "mixed"
    // literal, PrimitiveAt(slot) returns each slot's name,
    // IsMixed() is the typed predicate. Slot ordering is canonical:
    // 0 = noiseSeed, 1 = dataSeed, 2 = startSeed, 3 = lockSeed
    // (Single); Triple grows the middle range to 7 slots + lockSeed.
    fmt.Printf("mixed=%v primitive=%s\n", enc.IsMixed(), enc.Primitive)
    for i := 0; i < 4; i++ {
        fmt.Printf("  slot %d: %s\n", i, enc.PrimitiveAt(i))
    }

    blob := enc.Export()
    fmt.Printf("state blob: %d bytes\n", len(blob))

    plaintext := []byte("mixed-primitive Easy Mode payload")

    // Authenticated encrypt — 32-byte tag is computed across the
    // entire decrypted capacity and embedded inside the RGBWYOPA
    // container, preserving oracle-free deniability.
    encrypted, err := enc.EncryptAuth(plaintext)
    if err != nil {
        panic(err)
    }
    fmt.Printf("encrypted: %d bytes\n", len(encrypted))

    // Send encrypted payload + state blob
}

// Receiver

package main

import (
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/easy"
)

func main() {
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

    // Receive encrypted payload + state blob
    // var encrypted, blob []byte = ..., ...

    // Receiver constructs a matching mixed encryptor — every per-
    // slot primitive name plus key_bits and mac must agree with the
    // sender. Import validates each per-slot primitive against the
    // receiver's bound spec; mismatches surface as
    // easy.ErrMismatch{Field: "primitive"}.
    dec := easy.NewMixed(easy.MixedSpec{
        PrimitiveN: "blake3",
        PrimitiveD: "blake2s",
        PrimitiveS: "areion256",
        PrimitiveL: "blake2b256",
        KeyBits:    1024,
        MACName:    "hmac-blake3",
    })
    defer dec.Close()

    // Restore PRF keys, seed components, MAC key, and the per-
    // instance configuration overrides from the saved blob. Mixed
    // blobs carry mixed:true plus a primitives array; Import on a
    // single-primitive receiver (or vice versa) is rejected as a
    // primitive mismatch.
    if err := dec.Import(blob); err != nil {
        panic(err)
    }

    decrypted, err := dec.DecryptAuth(encrypted)
    if err != nil {
        panic(err)
    }
    fmt.Printf("decrypted: %s\n", string(decrypted))
}

Areion-SoEM-512 (Low-Level, No MAC)

// Sender

package main

import (
    "fmt"
    "github.com/everanium/itb"
)

func main() {
    // Optional: global configuration (all thread-safe, atomic)
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)
    itb.SetNonceBits(512)   // 512-bit nonce (default: 128-bit)
    itb.SetBarrierFill(4)   // CSPRNG fill margin (default: 1, valid: 1,2,4,8,16,32)

    itb.SetBitSoup(1)       // optional bit-level split ("bit-soup"; default: 0 = byte-level)
                            // automatically enabled for Single Ouroboros if
                            // itb.SetLockSoup(1) is enabled or vice versa

    itb.SetLockSoup(1)      // optional Insane Interlocked Mode: per-chunk PRF-keyed
                            // bit-permutation overlay on top of bit-soup;
                            // automatically enabled for Single Ouroboros if
                            // itb.SetBitSoup(1) is enabled or vice versa

    // Four independent CSPRNG-keyed Areion-SoEM-512 paired closures
    // (noise / data / start / lock). The third return value
    // (keyN/keyD/keyS/keyL) is the [64]byte fixed key — capture it
    // per seed for cross-process persistence. The batched arm
    // (batchN/batchD/batchS/batchL) wires the AVX-512 + VAES + ILP +
    // ZMM-batched chain-absorb dispatch through Seed.BatchHash.
    fnN, batchN, keyN := itb.MakeAreionSoEM512Hash() // random noise hash key generated
    fnD, batchD, keyD := itb.MakeAreionSoEM512Hash() // random data hash key generated
    fnS, batchS, keyS := itb.MakeAreionSoEM512Hash() // random start hash key generated
    fnL, batchL, keyL := itb.MakeAreionSoEM512Hash() // random lock hash key generated
    //fnN, batchN := itb.MakeAreionSoEM512HashWithKey(keyN) // [64]byte saved noise hash key
    //fnD, batchD := itb.MakeAreionSoEM512HashWithKey(keyD) // [64]byte saved data hash key
    //fnS, batchS := itb.MakeAreionSoEM512HashWithKey(keyS) // [64]byte saved start hash key
    //fnL, batchL := itb.MakeAreionSoEM512HashWithKey(keyL) // [64]byte saved lock hash key

    // Four independent CSPRNG-generated 2048-bit seeds.
    ns, _ := itb.NewSeed512(2048, fnN) // random noise CSPRNG seeds generated
    ds, _ := itb.NewSeed512(2048, fnD) // random data CSPRNG seeds generated
    ss, _ := itb.NewSeed512(2048, fnS) // random start CSPRNG seeds generated
    ls, _ := itb.NewSeed512(2048, fnL) // random lock CSPRNG seeds generated

    ns.BatchHash = batchN // must enable batch
    ds.BatchHash = batchD // must enable batch
    ss.BatchHash = batchS // must enable batch
    ls.BatchHash = batchL // must enable batch

    // Optional: dedicated lockSeed for the bit-permutation derivation
    // channel. Separates that PRF's keying material from the noiseSeed-
    // driven noise-injection channel without changing the public Encrypt
    // / Decrypt signatures. The bit-permutation overlay must be engaged
    // (itb.SetBitSoup(1) or itb.SetLockSoup(1) — both already on above)
    // before the first Encrypt; the build-PRF guard panics on encrypt-
    // time with itb.ErrLockSeedOverlayOff when an attach is present
    // without either flag.
    ns.AttachLockSeed(ls)

    plaintext := []byte("any text or binary data - including 0x00 bytes")
    //chunkSize := 4 * 1024 * 1024 // 4 MB - bulk local crypto, not small-frame network streaming

    // Encrypt into RGBWYOPA container
    encrypted, err := itb.Encrypt512(ns, ds, ss, plaintext)
    if err != nil {
        panic(err)
    }
    //var ciphertext []byte
    //err := itb.EncryptStream512(ns, ds, ss, plaintext, chunkSize, func(chunk []byte) error {
    //    ciphertext = append(ciphertext, chunk...)
    //    return nil
    //})
    fmt.Printf("encrypted: %d bytes\n", len(encrypted))

    // Cross-process persistence — Blob512 packs every PRF fixed key
    // ([64]byte each) plus every seed's Components ([]uint64) plus the
    // captured itb.Set* globals (NonceBits / BarrierFill / BitSoup /
    // LockSoup) into one self-describing JSON blob. Triple-Ouroboros
    // counterparts are Export3 / Import3 below; the lockSeed slot
    // rides in Blob512Opts.
    bSrc := &itb.Blob512{}
    blob, err := bSrc.Export(keyN, keyD, keyS, ns, ds, ss,
        itb.Blob512Opts{KeyL: keyL, LS: ls},
    )
    if err != nil {
        panic(err)
    }
    fmt.Printf("blob: %d bytes\n", len(blob))

    // Send encrypted payload + blob
}

// Receiver

package main

import (
    "fmt"
    "github.com/everanium/itb"
)

func main() {
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

    // Receive encrypted payload + blob
    // var encrypted, blob []byte = ..., ...

    // Restore everything from the blob — Blob512.Import applies the
    // sender's NonceBits / BarrierFill / BitSoup / LockSoup globals
    // unconditionally, then populates Mode + KeyN / KeyD / KeyS /
    // KeyL plus NS / DS / SS / LS with .Components filled in. Hash
    // and BatchHash on the seeds stay nil — caller wires them from
    // the saved key bytes through the matching factory.
    bDst := &itb.Blob512{}
    if err := bDst.Import(blob); err != nil {
        panic(err)
    }

    fnN, batchN := itb.MakeAreionSoEM512HashWithKey(bDst.KeyN)
    fnD, batchD := itb.MakeAreionSoEM512HashWithKey(bDst.KeyD)
    fnS, batchS := itb.MakeAreionSoEM512HashWithKey(bDst.KeyS)
    fnL, batchL := itb.MakeAreionSoEM512HashWithKey(bDst.KeyL)

    bDst.NS.Hash, bDst.NS.BatchHash = fnN, batchN
    bDst.DS.Hash, bDst.DS.BatchHash = fnD, batchD
    bDst.SS.Hash, bDst.SS.BatchHash = fnS, batchS
    bDst.LS.Hash, bDst.LS.BatchHash = fnL, batchL

    // Mirror the sender's AttachLockSeed wire-up — the bit-permutation
    // derivation channel must consult the same dedicated lockSeed
    // material on both sides.
    bDst.NS.AttachLockSeed(bDst.LS)

    // Decrypt from RGBWYOPA container
    decrypted, err := itb.Decrypt512(bDst.NS, bDst.DS, bDst.SS, encrypted)
    if err != nil {
        panic(err)
    }
    //var decrypted []byte
    //err = itb.DecryptStream512(bDst.NS, bDst.DS, bDst.SS, ciphertext, func(chunk []byte) error {
    //    decrypted = append(decrypted, chunk...)
    //    return nil
    //})
    fmt.Printf("decrypted: %s\n", string(decrypted))
}

Areion-SoEM-512 + HMAC-BLAKE3 (Low-Level, MAC Authenticated)

// Sender

package main

import (
    "crypto/rand"
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/macs"
)

func main() {
    // Optional: global configuration (all thread-safe, atomic)
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)
    itb.SetNonceBits(512)   // 512-bit nonce (default: 128-bit)
    itb.SetBarrierFill(4)   // CSPRNG fill margin (default: 1, valid: 1,2,4,8,16,32)

    itb.SetBitSoup(1)       // optional bit-level split ("bit-soup"; default: 0 = byte-level)
                            // automatically enabled for Single Ouroboros if
                            // itb.SetLockSoup(1) is enabled or vice versa

    itb.SetLockSoup(1)      // optional Insane Interlocked Mode: per-chunk PRF-keyed
                            // bit-permutation overlay on top of bit-soup;
                            // automatically enabled for Single Ouroboros if
                            // itb.SetBitSoup(1) is enabled or vice versa

    // Four independent CSPRNG-keyed Areion-SoEM-512 paired closures
    // (noise / data / start / lock). The third return value
    // (keyN/keyD/keyS/keyL) is the [64]byte fixed key — capture it
    // per seed for cross-process persistence.
    fnN, batchN, keyN := itb.MakeAreionSoEM512Hash() // random noise hash key generated
    fnD, batchD, keyD := itb.MakeAreionSoEM512Hash() // random data hash key generated
    fnS, batchS, keyS := itb.MakeAreionSoEM512Hash() // random start hash key generated
    fnL, batchL, keyL := itb.MakeAreionSoEM512Hash() // random lock hash key generated
    //fnN, batchN := itb.MakeAreionSoEM512HashWithKey(keyN) // [64]byte saved noise hash key
    //fnD, batchD := itb.MakeAreionSoEM512HashWithKey(keyD) // [64]byte saved data hash key
    //fnS, batchS := itb.MakeAreionSoEM512HashWithKey(keyS) // [64]byte saved start hash key
    //fnL, batchL := itb.MakeAreionSoEM512HashWithKey(keyL) // [64]byte saved lock hash key

    ns, _ := itb.NewSeed512(2048, fnN) // random noise CSPRNG seeds generated
    ds, _ := itb.NewSeed512(2048, fnD) // random data CSPRNG seeds generated
    ss, _ := itb.NewSeed512(2048, fnS) // random start CSPRNG seeds generated
    ls, _ := itb.NewSeed512(2048, fnL) // random lock CSPRNG seeds generated

    ns.BatchHash = batchN // must enable batch
    ds.BatchHash = batchD // must enable batch
    ss.BatchHash = batchS // must enable batch
    ls.BatchHash = batchL // must enable batch

    // Optional: dedicated lockSeed for the bit-permutation derivation
    // channel — same pattern as the no-MAC quick-start above.
    ns.AttachLockSeed(ls)

    // HMAC-BLAKE3 — 32-byte CSPRNG key, 32-byte tag.
    var macKey [32]byte
    rand.Read(macKey[:])
    mac, _ := macs.HMACBLAKE3(macKey[:])

    plaintext := []byte("any text or binary data - including 0x00 bytes")

    // Authenticated encrypt — 32-byte tag is computed across the entire
    // decrypted capacity and embedded inside the RGBWYOPA container,
    // preserving oracle-free deniability.
    encrypted, err := itb.EncryptAuthenticated512(ns, ds, ss, plaintext, mac)
    if err != nil {
        panic(err)
    }
    fmt.Printf("encrypted: %d bytes\n", len(encrypted))

    // Cross-process persistence — Blob512 packs every PRF fixed key,
    // every seed's Components, the dedicated lockSeed material, the
    // captured itb.Set* globals, and the MAC key + name into one
    // self-describing JSON blob.
    bSrc := &itb.Blob512{}
    blob, err := bSrc.Export(keyN, keyD, keyS, ns, ds, ss,
        itb.Blob512Opts{
            KeyL: keyL, LS: ls,
            MACKey: macKey[:], MACName: "hmac-blake3",
        },
    )
    if err != nil {
        panic(err)
    }
    fmt.Printf("blob: %d bytes\n", len(blob))

    // Send encrypted payload + blob
}

// Receiver

package main

import (
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/macs"
)

func main() {
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

    // Receive encrypted payload + blob
    // var encrypted, blob []byte = ..., ...

    // Restore everything from the blob — Import applies the sender's
    // globals + populates seeds + Key* fields + MACKey / MACName.
    bDst := &itb.Blob512{}
    if err := bDst.Import(blob); err != nil {
        panic(err)
    }

    fnN, batchN := itb.MakeAreionSoEM512HashWithKey(bDst.KeyN)
    fnD, batchD := itb.MakeAreionSoEM512HashWithKey(bDst.KeyD)
    fnS, batchS := itb.MakeAreionSoEM512HashWithKey(bDst.KeyS)
    fnL, batchL := itb.MakeAreionSoEM512HashWithKey(bDst.KeyL)

    bDst.NS.Hash, bDst.NS.BatchHash = fnN, batchN
    bDst.DS.Hash, bDst.DS.BatchHash = fnD, batchD
    bDst.SS.Hash, bDst.SS.BatchHash = fnS, batchS
    bDst.LS.Hash, bDst.LS.BatchHash = fnL, batchL
    bDst.NS.AttachLockSeed(bDst.LS)

    // Rebuild the MAC closure from the saved name + key. macs.Make
    // routes through the registry, so any of the shipped MAC primitives
    // (kmac256 / hmac-sha256 / hmac-blake3) restores via the same call.
    mac, _ := macs.Make(bDst.MACName, bDst.MACKey)

    // Authenticated decrypt — any single-bit tamper triggers MAC failure
    // (no oracle leak about which byte was tampered).
    decrypted, err := itb.DecryptAuthenticated512(bDst.NS, bDst.DS, bDst.SS, encrypted, mac)
    if err != nil {
        panic(err)
    }
    fmt.Printf("decrypted: %s\n", string(decrypted))
}

Other shipped MACs: macs.HMACSHA256(key), macs.KMAC256(key) — all three produce 32-byte tags. See macs/README.md for the full MAC matrix.

BLAKE2b-512 + HMAC-BLAKE3 (Low-Level, MAC Authenticated, 2048-bit Seeds)

// Sender

package main

import (
    "crypto/rand"
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/hashes"
    "github.com/everanium/itb/macs"
)

func main() {
    // Optional: global configuration (all thread-safe, atomic)
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)
    itb.SetNonceBits(512)   // 512-bit nonce (default: 128-bit)
    itb.SetBarrierFill(4)   // CSPRNG fill margin (default: 1, valid: 1,2,4,8,16,32)

    itb.SetBitSoup(1)       // optional bit-level split ("bit-soup"; default: 0 = byte-level)
                            // automatically enabled for Single Ouroboros if
                            // itb.SetLockSoup(1) is enabled or vice versa

    itb.SetLockSoup(1)      // optional Insane Interlocked Mode: per-chunk PRF-keyed
                            // bit-permutation overlay on top of bit-soup;
                            // automatically enabled for Single Ouroboros if
                            // itb.SetBitSoup(1) is enabled or vice versa

    // Four independent CSPRNG-keyed BLAKE2b-512 paired closures
    // (noise / data / start / lock). The third return value
    // (keyN/keyD/keyS/keyL) is the [64]byte fixed key — capture it
    // per seed for cross-process persistence. The batched arm
    // (batchN/batchD/batchS/batchL) wires the AVX-512 + ZMM-batched
    // chain-absorb dispatch through Seed.BatchHash.
    fnN, batchN, keyN := hashes.BLAKE2b512Pair() // random noise hash key generated
    fnD, batchD, keyD := hashes.BLAKE2b512Pair() // random data hash key generated
    fnS, batchS, keyS := hashes.BLAKE2b512Pair() // random start hash key generated
    fnL, batchL, keyL := hashes.BLAKE2b512Pair() // random lock hash key generated
    //fnN, batchN := hashes.BLAKE2b512PairWithKey(keyN) // [64]byte saved noise hash key
    //fnD, batchD := hashes.BLAKE2b512PairWithKey(keyD) // [64]byte saved data hash key
    //fnS, batchS := hashes.BLAKE2b512PairWithKey(keyS) // [64]byte saved start hash key
    //fnL, batchL := hashes.BLAKE2b512PairWithKey(keyL) // [64]byte saved lock hash key

    // 2048-bit seeds — 32 components × 64 bits, multiple of 8 for Seed512.
    ns, _ := itb.NewSeed512(2048, fnN) // random noise CSPRNG seeds generated
    ds, _ := itb.NewSeed512(2048, fnD) // random data CSPRNG seeds generated
    ss, _ := itb.NewSeed512(2048, fnS) // random start CSPRNG seeds generated
    ls, _ := itb.NewSeed512(2048, fnL) // random lock CSPRNG seeds generated

    ns.BatchHash = batchN // must enable batch
    ds.BatchHash = batchD // must enable batch
    ss.BatchHash = batchS // must enable batch
    ls.BatchHash = batchL // must enable batch

    // Optional: dedicated lockSeed for the bit-permutation derivation
    // channel — same pattern as the no-MAC quick-start above.
    ns.AttachLockSeed(ls)

    // HMAC-BLAKE3 — 32-byte CSPRNG key, 32-byte tag.
    var macKey [32]byte
    rand.Read(macKey[:])
    mac, _ := macs.HMACBLAKE3(macKey[:])

    plaintext := []byte("any text or binary data - including 0x00 bytes")

    // Authenticated encrypt — 32-byte tag is computed across the entire
    // decrypted capacity and embedded inside the RGBWYOPA container,
    // preserving oracle-free deniability.
    encrypted, err := itb.EncryptAuthenticated512(ns, ds, ss, plaintext, mac)
    if err != nil {
        panic(err)
    }
    fmt.Printf("encrypted: %d bytes\n", len(encrypted))

    // Cross-process persistence — Blob512 packs PRF fixed keys, seed
    // components, dedicated lockSeed material, captured itb.Set*
    // globals, and MAC key + name into one self-describing JSON blob.
    bSrc := &itb.Blob512{}
    blob, err := bSrc.Export(keyN, keyD, keyS, ns, ds, ss,
        itb.Blob512Opts{
            KeyL: keyL, LS: ls,
            MACKey: macKey[:], MACName: "hmac-blake3",
        },
    )
    if err != nil {
        panic(err)
    }
    fmt.Printf("blob: %d bytes\n", len(blob))

    // Send encrypted payload + blob
}

// Receiver

package main

import (
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/hashes"
    "github.com/everanium/itb/macs"
)

func main() {
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

    // Receive encrypted payload + blob
    // var encrypted, blob []byte = ..., ...

    bDst := &itb.Blob512{}
    if err := bDst.Import(blob); err != nil {
        panic(err)
    }

    fnN, batchN := hashes.BLAKE2b512PairWithKey(bDst.KeyN)
    fnD, batchD := hashes.BLAKE2b512PairWithKey(bDst.KeyD)
    fnS, batchS := hashes.BLAKE2b512PairWithKey(bDst.KeyS)
    fnL, batchL := hashes.BLAKE2b512PairWithKey(bDst.KeyL)

    bDst.NS.Hash, bDst.NS.BatchHash = fnN, batchN
    bDst.DS.Hash, bDst.DS.BatchHash = fnD, batchD
    bDst.SS.Hash, bDst.SS.BatchHash = fnS, batchS
    bDst.LS.Hash, bDst.LS.BatchHash = fnL, batchL
    bDst.NS.AttachLockSeed(bDst.LS)

    mac, _ := macs.Make(bDst.MACName, bDst.MACKey)

    // Authenticated decrypt — any single-bit tamper triggers MAC failure
    // (no oracle leak about which byte was tampered).
    decrypted, err := itb.DecryptAuthenticated512(bDst.NS, bDst.DS, bDst.SS, encrypted, mac)
    if err != nil {
        panic(err)
    }
    fmt.Printf("decrypted: %s\n", string(decrypted))
}

SipHash-2-4 (lightweight, 128-bit hash, no internal fixed key)

package main

import (
    "fmt"
    "github.com/everanium/itb"
    "github.com/everanium/itb/hashes"
)

func main() {
    // Optional: global configuration (all thread-safe, atomic)
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)
    itb.SetNonceBits(512)   // 512-bit nonce (default: 128-bit)
    itb.SetBarrierFill(4)   // CSPRNG fill margin (default: 1, valid: 1,2,4,8,16,32)

    itb.SetBitSoup(1)       // optional bit-level split ("bit-soup"; default: 0 = byte-level)
                            // automatically enabled for Single Ouroboros if
                            // itb.SetLockSoup(1) is enabled or vice versa

    itb.SetLockSoup(1)      // optional Insane Interlocked Mode: per-chunk PRF-keyed
                            // bit-permutation overlay on top of bit-soup;
                            // automatically enabled for Single Ouroboros if
                            // itb.SetBitSoup(1) is enabled or vice versa

    // SipHash-2-4 has no internal fixed key — the seed components themselves
    // are the entire keying material. Three independent factory calls paired
    // with three CSPRNG-generated seeds give three independent 1024-bit
    // effective keys. The batched arm (batchN/batchD/batchS) wires the
    // AVX-512 ZMM-batched chain-absorb dispatch through Seed.BatchHash.
    fnN, batchN := hashes.SipHash24Pair()
    fnD, batchD := hashes.SipHash24Pair()
    fnS, batchS := hashes.SipHash24Pair()

    ns, _ := itb.NewSeed128(1024, fnN); ns.BatchHash = batchN // random noise CSPRNG seeds generated, batch enabled
    ds, _ := itb.NewSeed128(1024, fnD); ds.BatchHash = batchD // random data CSPRNG seeds generated, batch enabled
    ss, _ := itb.NewSeed128(1024, fnS); ss.BatchHash = batchS // random start CSPRNG seeds generated, batch enabled

    // Optional: dedicated lockSeed for the bit-permutation derivation
    // channel — same flow as the Areion-SoEM-512 quick-starts above.
    fnL, batchL := hashes.SipHash24Pair()
    ls, _ := itb.NewSeed128(1024, fnL); ls.BatchHash = batchL
    ns.AttachLockSeed(ls)

    plaintext := []byte("any text or binary data - including 0x00 bytes")

    encrypted, _ := itb.Encrypt128(ns, ds, ss, plaintext)
    fmt.Printf("encrypted: %d bytes\n", len(encrypted))

    // Cross-process persistence — Blob128 packs every seed's Components
    // (SipHash-2-4 has no fixed PRF key; the seed components are the
    // entire keying material — KeyN/KeyD/KeyS/KeyL stay nil) plus the
    // optional dedicated lockSeed and the captured itb.Set* globals
    // into one self-describing JSON blob.
    bSrc := &itb.Blob128{}
    blob, _ := bSrc.Export(nil, nil, nil, ns, ds, ss,
        itb.Blob128Opts{LS: ls})

    // Receiver — Import reverses Export. Globals are restored
    // unconditionally; Hash / BatchHash on each seed stay nil so the
    // caller wires SipHash-2-4 closures from a fresh factory call.
    bDst := &itb.Blob128{}
    _ = bDst.Import(blob)

    fnN2, batchN2 := hashes.SipHash24Pair()
    fnD2, batchD2 := hashes.SipHash24Pair()
    fnS2, batchS2 := hashes.SipHash24Pair()
    fnL2, batchL2 := hashes.SipHash24Pair()
    bDst.NS.Hash, bDst.NS.BatchHash = fnN2, batchN2
    bDst.DS.Hash, bDst.DS.BatchHash = fnD2, batchD2
    bDst.SS.Hash, bDst.SS.BatchHash = fnS2, batchS2
    bDst.LS.Hash, bDst.LS.BatchHash = fnL2, batchL2
    bDst.NS.AttachLockSeed(bDst.LS)

    decrypted, _ := itb.Decrypt128(bDst.NS, bDst.DS, bDst.SS, encrypted)
    fmt.Printf("decrypted: %s\n", string(decrypted))
}

Quick Start — Triple Ouroboros (7 seeds, 3× security)

// Triple Ouroboros: 7 seeds (1 noise + 3 data + 3 start) plus an
// optional 8th dedicated lockSeed, 512-bit for speed.

itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)

// Light secure bit-permutation mode without performance trade-off (Recommended to use with Triple Ouroboros)
itb.SetBitSoup(1)       // optional mode: bit-level split ("bit soup"), opt-in SAT-resistance reserve (default: 0 = byte-level)
                        // automatically enabled for Single Ouroboros if itb.SetLockSoup(1) is enabled or vice versa
// Most secure bit-permutation mode with performance trade-off ~2×-7× slower
itb.SetLockSoup(1)      // optional Insane Interlocked Mode overlay: per-chunk PRF-keyed bit-permutation; ~2×-7× slower
                        // automatically engages itb.SetBitSoup(1)

// Eight independent CSPRNG-keyed Areion-SoEM-512 paired closures
// (1 noise + 3 data + 3 start + 1 lock).
fnN,  batchN,  keyN  := itb.MakeAreionSoEM512Hash()
fnD1, batchD1, keyD1 := itb.MakeAreionSoEM512Hash()
fnD2, batchD2, keyD2 := itb.MakeAreionSoEM512Hash()
fnD3, batchD3, keyD3 := itb.MakeAreionSoEM512Hash()
fnS1, batchS1, keyS1 := itb.MakeAreionSoEM512Hash()
fnS2, batchS2, keyS2 := itb.MakeAreionSoEM512Hash()
fnS3, batchS3, keyS3 := itb.MakeAreionSoEM512Hash()
fnL,  batchL,  keyL  := itb.MakeAreionSoEM512Hash()

ns,  _ := itb.NewSeed512(2048, fnN);  ns.BatchHash  = batchN
ds1, _ := itb.NewSeed512(2048, fnD1); ds1.BatchHash = batchD1
ds2, _ := itb.NewSeed512(2048, fnD2); ds2.BatchHash = batchD2
ds3, _ := itb.NewSeed512(2048, fnD3); ds3.BatchHash = batchD3
ss1, _ := itb.NewSeed512(2048, fnS1); ss1.BatchHash = batchS1
ss2, _ := itb.NewSeed512(2048, fnS2); ss2.BatchHash = batchS2
ss3, _ := itb.NewSeed512(2048, fnS3); ss3.BatchHash = batchS3
ls,  _ := itb.NewSeed512(2048, fnL);  ls.BatchHash  = batchL

// Optional: dedicated lockSeed for the bit-permutation derivation
// channel — same flow as the Single Ouroboros quick-starts above.
ns.AttachLockSeed(ls)

encrypted, _ := itb.Encrypt3x512(ns, ds1, ds2, ds3, ss1, ss2, ss3, plaintext)

// Cross-process persistence — Blob512.Export3 packs the 7 seeds, the
// 7 hash keys, the dedicated lockSeed material, and the captured
// itb.Set* globals into one self-describing JSON blob. Add MACKey /
// MACName to Blob512Opts when an authenticated variant is in use.
bSrc := &itb.Blob512{}
blob, _ := bSrc.Export3(
    keyN, keyD1, keyD2, keyD3, keyS1, keyS2, keyS3,
    ns, ds1, ds2, ds3, ss1, ss2, ss3,
    itb.Blob512Opts{KeyL: keyL, LS: ls},
)

// Receiver — Import3 reverses Export3. Globals are restored
// unconditionally; Hash / BatchHash on each seed stay nil so the
// caller wires them from the saved Key* bytes.
bDst := &itb.Blob512{}
_ = bDst.Import3(blob)

fnN2,  batchN2  := itb.MakeAreionSoEM512HashWithKey(bDst.KeyN)
fnD1b, batchD1b := itb.MakeAreionSoEM512HashWithKey(bDst.KeyD1)
fnD2b, batchD2b := itb.MakeAreionSoEM512HashWithKey(bDst.KeyD2)
fnD3b, batchD3b := itb.MakeAreionSoEM512HashWithKey(bDst.KeyD3)
fnS1b, batchS1b := itb.MakeAreionSoEM512HashWithKey(bDst.KeyS1)
fnS2b, batchS2b := itb.MakeAreionSoEM512HashWithKey(bDst.KeyS2)
fnS3b, batchS3b := itb.MakeAreionSoEM512HashWithKey(bDst.KeyS3)
fnLb,  batchLb  := itb.MakeAreionSoEM512HashWithKey(bDst.KeyL)

bDst.NS.Hash,  bDst.NS.BatchHash  = fnN2,  batchN2
bDst.DS1.Hash, bDst.DS1.BatchHash = fnD1b, batchD1b
bDst.DS2.Hash, bDst.DS2.BatchHash = fnD2b, batchD2b
bDst.DS3.Hash, bDst.DS3.BatchHash = fnD3b, batchD3b
bDst.SS1.Hash, bDst.SS1.BatchHash = fnS1b, batchS1b
bDst.SS2.Hash, bDst.SS2.BatchHash = fnS2b, batchS2b
bDst.SS3.Hash, bDst.SS3.BatchHash = fnS3b, batchS3b
bDst.LS.Hash,  bDst.LS.BatchHash  = fnLb,  batchLb
bDst.NS.AttachLockSeed(bDst.LS)

decrypted, _ := itb.Decrypt3x512(
    bDst.NS, bDst.DS1, bDst.DS2, bDst.DS3, bDst.SS1, bDst.SS2, bDst.SS3, encrypted,
)
// Security: P × 2^(3×512) = P × 2^1536. Faster than Single 1024-bit, stronger security.

Mixing PRF Primitives

Each seed has its own hash function — different PRF implementations are allowed for different seeds within the same hash width, including the dedicated lockSeed when one is attached via AttachLockSeed. The receiver must use the same assignment. Both arms of the *Pair() factory propagate to the seed via BatchHash so the AVX-512 ZMM-batched dispatch stays active per primitive. The Lock Soup overlay's per-chunk derivation captures the attached lockSeed's Hash (and components) — primitive divergence between the noise-injection channel and the bit-permutation channel is observable end-to-end and offers algorithm-diversity defence-in-depth on top of the independent keying material.

Single Ouroboros (3 seeds + optional dedicated lockSeed):

fnN, batchN, _ := hashes.BLAKE3256Pair()   // noiseSeed: BLAKE3
fnD, batchD, _ := hashes.BLAKE2s256Pair()  // dataSeed:  BLAKE2s
fnS, batchS, _ := hashes.BLAKE3256Pair()   // startSeed: BLAKE3

ns, _ := itb.NewSeed256(1024, fnN)
ds, _ := itb.NewSeed256(1024, fnD)
ss, _ := itb.NewSeed256(1024, fnS)
ns.BatchHash, ds.BatchHash, ss.BatchHash = batchN, batchD, batchS

// Optional: dedicated lockSeed for the bit-permutation derivation
// channel — pick any 256-bit primitive; the Lock Soup overlay
// honestly routes its per-chunk PRF through ls.Hash and ls.Components,
// so the lockSeed primitive may legitimately differ from the
// noiseSeed primitive.
fnL, batchL, _ := hashes.BLAKE2s256Pair()  // lockSeed: BLAKE2s
ls, _ := itb.NewSeed256(1024, fnL); ls.BatchHash = batchL
ns.AttachLockSeed(ls)

encrypted, _ := itb.Encrypt256(ns, ds, ss, plaintext)

Triple Ouroboros (7 seeds + optional dedicated lockSeed):

fnN,  batchN,  _ := hashes.BLAKE3256Pair()   // shared noise: BLAKE3
fnD1, batchD1, _ := hashes.BLAKE2s256Pair()  // ring 1 data:  BLAKE2s
fnD2, batchD2, _ := hashes.BLAKE3256Pair()   // ring 2 data:  BLAKE3
fnD3, batchD3, _ := hashes.BLAKE2s256Pair()  // ring 3 data:  BLAKE2s
fnS1, batchS1, _ := hashes.BLAKE3256Pair()   // ring 1 start: BLAKE3
fnS2, batchS2, _ := hashes.BLAKE2s256Pair()  // ring 2 start: BLAKE2s
fnS3, batchS3, _ := hashes.BLAKE3256Pair()   // ring 3 start: BLAKE3

ns,  _ := itb.NewSeed256(512, fnN)
ds1, _ := itb.NewSeed256(512, fnD1)
ds2, _ := itb.NewSeed256(512, fnD2)
ds3, _ := itb.NewSeed256(512, fnD3)
ss1, _ := itb.NewSeed256(512, fnS1)
ss2, _ := itb.NewSeed256(512, fnS2)
ss3, _ := itb.NewSeed256(512, fnS3)
ns.BatchHash, ds1.BatchHash, ds2.BatchHash, ds3.BatchHash = batchN, batchD1, batchD2, batchD3
ss1.BatchHash, ss2.BatchHash, ss3.BatchHash = batchS1, batchS2, batchS3

// Optional: dedicated lockSeed for the bit-permutation derivation
// channel — same mixing rule as the Single Ouroboros block above.
// ls.Hash and ls.Components both flow through the Lock Soup overlay,
// so a primitive choice for ls is meaningful and not just keying-
// material isolation.
fnL, batchL, _ := hashes.BLAKE3256Pair()    // lockSeed: BLAKE3
ls, _ := itb.NewSeed256(512, fnL); ls.BatchHash = batchL
ns.AttachLockSeed(ls)

encrypted, _ := itb.Encrypt3x256(ns, ds1, ds2, ds3, ss1, ss2, ss3, plaintext)

For Triple Ouroboros, use the most performance-balanced PRF primitives across the three dataSeed rings — this ensures all three parallel goroutines finish at similar times. BLAKE3 / BLAKE2s sit close on the AVX-512 ZMM throughput envelope (see BENCH.md / BENCH3.md) and are a natural balanced pair.

How It Works

ITB encrypts data into raw RGBWYOPA pixel containers (8 channels per pixel: Red, Green, Blue, White, Yellow, Orange, Purple, Alpha — mnemonic labels for an 8-byte unit; the format is not tied to image processing) generated from crypto/rand. Each 8-bit channel carries 7 data bits and 1 noise bit, yielding 56 data bits per pixel at 1.14× overhead. Each pixel's bit-plane selection and per-channel XOR masks are derived from a chained hash of the seed and a per-message nonce. The random container creates an information-theoretic barrier: hash outputs are absorbed by modifications of random pixel values — the original container bytes are never transmitted, so the modifications are unknown, and the hash output is unobservable.

The data is embedded starting at a seed-dependent pixel offset with wrap-around — the physical layout in the container is completely non-sequential. An observer sees uniformly random pixel values with no way to determine which pixels carry data, in what order, or what bit-plane is used.

Hash Width Variants

The library provides three parallel API sets for different hash output widths. All share the same pixel format, framing, and security properties — the difference is in ChainHash intermediate state width.

API Seeds Hash Type State Effective Max Key Target Hash Functions
Encrypt256 / Decrypt256 3 HashFunc256 (256-bit) 256-bit 1024 bits Areion-SoEM-256, BLAKE2s, BLAKE3 keyed, BLAKE2b-256, ChaCha20
Encrypt512 / Decrypt512 3 HashFunc512 (512-bit) 512-bit 2048 bits Areion-SoEM-512, BLAKE2b-512
Encrypt128 / Decrypt128 3 HashFunc128 (128-bit) 128-bit 1024 bits SipHash-2-4, AES-CMAC
Encrypt3x256 / Decrypt3x256 7 HashFunc256 (256-bit) 256-bit 1024 bits Areion-SoEM-256, BLAKE2s, BLAKE3 keyed, BLAKE2b-256, ChaCha20
Encrypt3x512 / Decrypt3x512 7 HashFunc512 (512-bit) 512-bit 2048 bits Areion-SoEM-512, BLAKE2b-512
Encrypt3x128 / Decrypt3x128 7 HashFunc128 (128-bit) 128-bit 1024 bits SipHash-2-4, AES-CMAC

Each variant also has authenticated versions (EncryptAuthenticated128/DecryptAuthenticated128, EncryptAuthenticated3x128/DecryptAuthenticated3x128, etc.) and streaming versions (EncryptStream128/DecryptStream128, EncryptStream3x128/DecryptStream3x128, etc.).

Optimized Hash Wrappers

Hash functions like AES and BLAKE3 have expensive key setup. Creating a new cipher/hasher on every call wastes time on initialization. The cached wrapper pattern fixes this: create the cipher once with a fixed random key, mix seed components into the data instead. Each of the three seeds must get its own wrapper instance (independent key).

The hashes/ subpackage ships ready cached factories — hashes.SipHash24(), hashes.AESCMAC(), hashes.ChaCha20(), hashes.BLAKE2s(), hashes.BLAKE2b256(), hashes.BLAKE2b512(), hashes.BLAKE3() — each returning a closure with a freshly-generated random key. For the recommended default Areion-SoEM, use the flagship factories shipped directly from the itb root package (see below). A WithKey variant is also exported for every primitive (hashes.AESCMACWithKey(key) etc.) for serialization paths where the fixed key must persist across processes.

Areion-SoEM (256/512-bit, VAES-accelerated batched dispatch — Recommended)

Areion-SoEM is a formally proven beyond-birthday-bound PRF based on AES round functions. ITB ships a built-in 4-way batched implementation (AreionSoEM256x4 / AreionSoEM512x4) that runs ~2× faster than four serial calls on x86_64 hardware with VAES + AVX-512 (Intel Rocket Lake / Tiger Lake+, AMD Zen 4+) and ~1.3× over scalar AES-NI on hosts with VAES + AVX2 but no AVX-512 (AMD Zen 3, Intel Alder Lake P/E-cores). The paired-factory helpers MakeAreionSoEM256Hash / MakeAreionSoEM512Hash return (HashFunc, BatchHashFunc, fixedKey) so each seed wires both arms with the same fixed key — ITB's processChunk{256,512} then dispatches per-pixel hashing four pixels per batched call. Pass nothing for a CSPRNG-generated fixedKey (returned for cross-process persistence — save it!) or pass a saved [32]byte / [64]byte on the restore path.

Recent ASM work in internal/areionasm/ lifts both arms substantially: the SoEM batched dispatch interleaves four VAES lanes per round for 3-4× over the prior sequential layout, and fused single-shot AVX-512 chain kernels (areion_chain{256,512}_{20,36,68}_amd64.s) collapse a full per-pixel ChainHash into one ASM call for 5-10× over the per-call Go path. The 20 / 36 / 68 byte specialisations cover SetNonceBits(128 / 256 / 512) respectively; state is held in ZMM registers across all CBC-MAC absorb rounds with zero memory round-trips.

The example below pairs Areion-SoEM-256 with the streaming API (EncryptStream256 / DecryptStream256) at a deliberately modest 1024-bit seed width — same Quick Start shape, just one tier down on key size and routed through the chunk-emitting callback variant suitable for socket / pipe / file delivery:

package main

import (
    "fmt"
    "github.com/everanium/itb"
)

func main() {
    // Optional: global configuration (all thread-safe, atomic)
    itb.SetMaxWorkers(8)    // limit to 8 CPU cores (default: all CPUs)
    itb.SetNonceBits(512)   // 512-bit nonce (default: 128-bit)
    itb.SetBarrierFill(4)   // CSPRNG fill margin (default: 1, valid: 1,2,4,8,16,32)

    itb.SetBitSoup(1)       // optional bit-level split ("bit-soup"; default: 0 = byte-level)
                            // automatically enabled for Single Ouroboros if
                            // itb.SetLockSoup(1) is enabled or vice versa

    itb.SetLockSoup(1)      // optional Insane Interlocked Mode: per-chunk PRF-keyed
                            // bit-permutation overlay on top of bit-soup;
                            // automatically enabled for Single Ouroboros if
                            // itb.SetBitSoup(1) is enabled or vice versa


    // Four independent CSPRNG-keyed Areion-SoEM-256 paired closures
    // (3 main seeds + 1 optional dedicated lockSeed). The third return
    // value (keyN/keyD/keyS/keyL) is the [32]byte fixed key — capture
    // it per seed for cross-process persistence. The batched arm
    // (batchN/batchD/batchS/batchL) wires the AVX-512 + VAES + ILP +
    // ZMM-batched chain-absorb dispatch through Seed.BatchHash.
    fnN, batchN, keyN := itb.MakeAreionSoEM256Hash() // random noise hash key generated
    fnD, batchD, keyD := itb.MakeAreionSoEM256Hash() // random data hash key generated
    fnS, batchS, keyS := itb.MakeAreionSoEM256Hash() // random start hash key generated
    fnL, batchL, keyL := itb.MakeAreionSoEM256Hash() // random lock hash key generated
    //fnN, batchN := itb.MakeAreionSoEM256HashWithKey(keyN) // [32]byte saved noise hash key
    //fnD, batchD := itb.MakeAreionSoEM256HashWithKey(keyD) // [32]byte saved data hash key
    //fnS, batchS := itb.MakeAreionSoEM256HashWithKey(keyS) // [32]byte saved start hash key
    //fnL, batchL := itb.MakeAreionSoEM256HashWithKey(keyL) // [32]byte saved lock hash key

    // 1024-bit seeds — 16 components × 64 bits, multiple of 4 for Seed256.
    ns, _ := itb.NewSeed256(1024, fnN); ns.BatchHash = batchN // random noise CSPRNG seeds, batch enabled
    ds, _ := itb.NewSeed256(1024, fnD); ds.BatchHash = batchD // random data CSPRNG seeds, batch enabled
    ss, _ := itb.NewSeed256(1024, fnS); ss.BatchHash = batchS // random start CSPRNG seeds, batch enabled
    ls, _ := itb.NewSeed256(1024, fnL); ls.BatchHash = batchL // random lock CSPRNG seeds, batch enabled

    // Optional: dedicated lockSeed for the bit-permutation derivation
    // channel — same flow as the Areion-SoEM-512 quick-starts above.
    ns.AttachLockSeed(ls)

    plaintext := []byte("any text or binary data - including 0x00 bytes")
    chunkSize := 4 * 1024 * 1024 // 4 MB — bulk local crypto, not small-frame network streaming

    // EncryptStream256 — emits successive ciphertext chunks via callback.
    // Useful for file-sized payloads that shouldn't materialise in memory.
    var ciphertext []byte
    err := itb.EncryptStream256(ns, ds, ss, plaintext, chunkSize, func(chunk []byte) error {
        ciphertext = append(ciphertext, chunk...)
        return nil
    })
    if err != nil {
        panic(err)
    }
    fmt.Printf("encrypted: %d bytes\n", len(ciphertext))

    // Cross-process persistence — Blob256 packs every seed's hash key
    // ([32]byte for Areion-SoEM-256) and Components ([]uint64) plus
    // the optional dedicated lockSeed and the captured itb.Set* globals
    // into one self-describing JSON blob.
    bSrc := &itb.Blob256{}
    blob, _ := bSrc.Export(keyN, keyD, keyS, ns, ds, ss,
        itb.Blob256Opts{KeyL: keyL, LS: ls})

    // Receiver — Import reverses Export. Globals are restored
    // unconditionally; Hash / BatchHash on each seed stay nil so the
    // caller wires them from the saved Key* bytes.
    bDst := &itb.Blob256{}
    _ = bDst.Import(blob)

    fnN2, batchN2 := itb.MakeAreionSoEM256HashWithKey(bDst.KeyN)
    fnD2, batchD2 := itb.MakeAreionSoEM256HashWithKey(bDst.KeyD)
    fnS2, batchS2 := itb.MakeAreionSoEM256HashWithKey(bDst.KeyS)
    fnL2, batchL2 := itb.MakeAreionSoEM256HashWithKey(bDst.KeyL)
    bDst.NS.Hash, bDst.NS.BatchHash = fnN2, batchN2
    bDst.DS.Hash, bDst.DS.BatchHash = fnD2, batchD2
    bDst.SS.Hash, bDst.SS.BatchHash = fnS2, batchS2
    bDst.LS.Hash, bDst.LS.BatchHash = fnL2, batchL2
    bDst.NS.AttachLockSeed(bDst.LS)

    // DecryptStream256 — emits successive plaintext chunks via callback.
    // Production callers drive emit from a file / mapped-region read loop.
    var decrypted []byte
    err = itb.DecryptStream256(bDst.NS, bDst.DS, bDst.SS, ciphertext, func(chunk []byte) error {
        decrypted = append(decrypted, chunk...)
        return nil
    })
    if err != nil {
        panic(err)
    }
    fmt.Printf("decrypted: %s\n", string(decrypted))
}

The Areion-SoEM-512 variant uses MakeAreionSoEM512Hash() paired with itb.Encrypt512 / itb.Decrypt512 and is wired identically. The batched arm of the returned pair shares the same internally-generated random fixed key as the single arm, so per-pixel hashes match bit-exact between the two dispatch paths (verified by the parity test suite). Triple Ouroboros wires the same way: each of the seven seeds receives an independent paired factory call.

Backward compatibility — no VAES required. The same code works on every platform; only the throughput tier changes:

CPU / build Path Throughput tier
amd64 + VAES + AVX-512 (Intel Ice Lake+, AMD Zen 4+) SoEM batched: internal/areionasm/areion_soem{256,512}_amd64.s + fused chain: internal/areionasm/areion_chain{256,512}_{20,36,68}_amd64.s Top tier: 4-way VAES interleaved on ZMM and fused-state chain kernel (one ASM call per pixel; no memory round-trips between absorb rounds)
amd64 + VAES + AVX2 only (AMD Zen 3, Alder Lake E-cores) Per-half permute: internal/areionasm/areion_amd64.s (Areion256Permutex4Avx2 / Areion512Permutex4Avx2); SoEM XOR finalize on the Go side 4-way VAES on YMM (2 AES blocks per VAESENC × 2 sequential lane pairs = 4 blocks per state half), ~2× over scalar AES-NI; SoEM-state interleaving and fused chain kernel are AVX-512-only and fall back to per-call Go path
amd64 without VAES (older Intel / AMD) Go fallback via aes.Round4HW(state, zeroKey) (internal/areionasm/areion_amd64.s base permutation) 4× sequential AES-NI per round (no SIMD width gain, still hardware-accelerated)
Pure software / CGO_ENABLED=0 Same Go fallback (process_generic.go batched dispatch wired) Slowest tier, correct output preserved

Runtime CPU detection (areionasm.HasVAESAVX512 and areionasm.HasVAESAVX2NoAVX512) selects the right path once at package init via the upstream github.com/jedisct1/go-aes CPUID checks — no per-call branching cost. The bit-exact parity invariant BatchHash(data)[i] == Hash(data[i]) holds on every platform; ITB's parity test suite (TestAreionSoEM{256,512}x4Parity plus the direct-call parity tests for each tier and a 3-way cross-path parity test on hosts where all three implementations are runnable) verifies this on every test run.

If the underlying primitive must be wired manually (custom key management, keyless probe, etc.) call aes.AreionSoEM256 / aes.AreionSoEM512 from github.com/jedisct1/go-aes directly — same primitive, no batched dispatch, useful only when the paired-factory pattern does not fit the deployment.

Pluggable PRF primitives via hashes/

The hashes/ subpackage ships paired cached factories for every PRF-grade primitive ITB exposes through its FFI surface. Each <Primitive>Pair() factory pre-keys its primitive once at construction, returns a (single, batched, key) triple — the batched arm wires the AVX-512 ZMM-batched chain-absorb dispatch through Seed.BatchHash automatically — reuses a sync.Pool of scratch buffers, and is safe to call concurrently. Pass nothing for a CSPRNG-generated key (returned for cross-process persistence — capture and save it); pass a saved key on the restore path. The <Primitive>PairWithKey counterpart takes the fixed key as a single non-variadic argument for unambiguously explicit-key call sites. SipHash-2-4 is the one exception — its keying material is the seed components themselves, no internal fixed key, so SipHash24Pair() takes no arguments and returns a (single, batched) pair without a third key element.

Single-arm-only factories (AESCMAC(), BLAKE2b256(), BLAKE2b512(), BLAKE2s(), BLAKE3(), ChaCha20(), SipHash24()) remain available for callers that don't need the batched dispatch — they return only the single-call closure without exposing the ZMM-batched arm.

In FFI-stable index order:

# Variadic factory Explicit-key counterpart Returns (variadic form) Native width
0 Areion256Pair(key ...[32]byte) Areion256PairWithKey(key [32]byte) (HashFunc256, BatchHashFunc256, [32]byte) 256
1 Areion512Pair(key ...[64]byte) Areion512PairWithKey(key [64]byte) (HashFunc512, BatchHashFunc512, [64]byte) 512
2 SipHash24Pair() — (seed components are the entire key) (HashFunc128, BatchHashFunc128) 128
3 AESCMACPair(key ...[16]byte) AESCMACPairWithKey(key [16]byte) (HashFunc128, BatchHashFunc128, [16]byte) 128
4 BLAKE2b256Pair(key ...[32]byte) BLAKE2b256PairWithKey(key [32]byte) (HashFunc256, BatchHashFunc256, [32]byte) 256
5 BLAKE2b512Pair(key ...[64]byte) BLAKE2b512PairWithKey(key [64]byte) (HashFunc512, BatchHashFunc512, [64]byte) 512
6 BLAKE2s256Pair(key ...[32]byte) BLAKE2s256PairWithKey(key [32]byte) (HashFunc256, BatchHashFunc256, [32]byte) 256
7 BLAKE3256Pair(key ...[32]byte) BLAKE3256PairWithKey(key [32]byte) (HashFunc256, BatchHashFunc256, [32]byte) 256
8 ChaCha20256Pair(key ...[32]byte) ChaCha20256PairWithKey(key [32]byte) (HashFunc256, BatchHashFunc256, [32]byte) 256

Name-keyed dispatch (used by the FFI layer; works for any code that selects the primitive at runtime). The key is []byte, size validated against the primitive's native length. Make<N>Pair returns the batched arm alongside the single arm; Make<N> (no Pair suffix) is the single-arm-only convenience that drops the batched arm:

Function Returns Covers
Make128(name, key ...[]byte) (HashFunc128, []byte, error) 128-bit primitives, single arm only
Make128Pair(name, key ...[]byte) (HashFunc128, BatchHashFunc128, []byte, error) 128-bit primitives, single + batched (SipHash-2-4, AES-CMAC)
Make256(name, key ...[]byte) (HashFunc256, []byte, error) 256-bit primitives, single arm only
Make256Pair(name, key ...[]byte) (HashFunc256, BatchHashFunc256, []byte, error) 256-bit primitives, single + batched (Areion-SoEM-256, BLAKE2b-256, BLAKE2s, BLAKE3, ChaCha20)
Make512(name, key ...[]byte) (HashFunc512, []byte, error) 512-bit primitives, single arm only
Make512Pair(name, key ...[]byte) (HashFunc512, BatchHashFunc512, []byte, error) 512-bit primitives, single + batched (Areion-SoEM-512, BLAKE2b-512)
Find(name) (Spec, bool) Spec lookup for key-size / native-width metadata

Authenticated MACs via macs/

The macs/ subpackage ships three MAC primitives with a fixed 32-byte tag and FFI-stable index order. All three pre-key the primitive once at construction and are safe to call concurrently. The factory takes the key as []byte (no variadic random-key path — the caller generates the key via crypto/rand.Read and passes it explicitly):

# Factory Returns Key size Tag size
0 KMAC256(key []byte) (MACFunc, error) ≥16 B 32 B
KMAC256WithCustomization(key, customization []byte) (MACFunc, error) ≥16 B 32 B
1 HMACSHA256(key []byte) (MACFunc, error) ≥16 B 32 B
2 HMACBLAKE3(key []byte) (MACFunc, error) 32 B 32 B

Name-keyed dispatch:

Function Returns Purpose
Make(name, key []byte) (MACFunc, error) Name-keyed dispatch (FFI / runtime selection)
Find(name) (Spec, bool) Spec lookup for key-size metadata

See macs/README.md for full authenticated-encryption examples (EncryptAuthenticated{128,256,512} / DecryptAuthenticated{128,256,512}) and the MAC-Inside-Encrypt placement-hiding rationale.

Custom factory pattern (advanced)

Write your own HashFunc when you need a primitive not covered by the hashes/ subpackage, or want a different keying / pooling strategy. The pattern below is what hashes.BLAKE3() itself ships, kept here as a reference. Three techniques worth noting:

  • sync.Pool amortises per-call allocation of the scratch buffer
  • blake3.NewKeyed produces a hasher template; Clone() per call sidesteps the data race that Reset() on a shared hasher would cause under ITB's parallel goroutines in process256
  • the payload region is zero-padded out to seedInjectBytes (32) so all four seed uint64's contribute even when len(data) is shorter than 32 (a 20-byte ITB pixel input would otherwise drop seed[2..3] silently)
func makeBlake3Hash() itb.HashFunc256 {
    var key [32]byte
    rand.Read(key[:])
    template, _ := blake3.NewKeyed(key[:])
    pool := &sync.Pool{New: func() any { b := make([]byte, 0, 128); return &b }}

    return func(data []byte, seed [4]uint64) [4]uint64 {
        h := template.Clone()
        const seedInjectBytes = 32
        payloadLen := len(data)
        if payloadLen < seedInjectBytes { payloadLen = seedInjectBytes }
        ptr := pool.Get().(*[]byte)
        mixed := *ptr
        if cap(mixed) < payloadLen { mixed = make([]byte, payloadLen) } else { mixed = mixed[:payloadLen] }
        for i := len(data); i < payloadLen; i++ { mixed[i] = 0 }
        copy(mixed[:len(data)], data)
        for i := 0; i < 4; i++ {
            off := i * 8
            binary.LittleEndian.PutUint64(mixed[off:], binary.LittleEndian.Uint64(mixed[off:])^seed[i])
        }
        h.Write(mixed)
        *ptr = mixed; pool.Put(ptr)
        var buf [32]byte
        h.Sum(buf[:0])
        return [4]uint64{
            binary.LittleEndian.Uint64(buf[0:]),  binary.LittleEndian.Uint64(buf[8:]),
            binary.LittleEndian.Uint64(buf[16:]), binary.LittleEndian.Uint64(buf[24:]),
        }
    }
}

ns, _ := itb.NewSeed256(2048, makeBlake3Hash())
ds, _ := itb.NewSeed256(2048, makeBlake3Hash())
ss, _ := itb.NewSeed256(2048, makeBlake3Hash())

Parallelism Control

itb.SetMaxWorkers(4) // limit to 4 CPU cores for pixel processing

By default, ITB uses all available CPU cores. On shared servers, use SetMaxWorkers to limit CPU usage. Pass 0 to use all CPUs (default). Valid range: 0–256. Thread-safe (atomic). Query with itb.GetMaxWorkers().

Nonce Configuration

itb.SetNonceBits(256) // 256-bit nonce (~2^128 birthday bound)

Default nonce is 128 bits (birthday collision at ~2^64 messages). For higher collision resistance, use SetNonceBits. Valid values: 128, 256, 512. Panics on invalid input. Both sender and receiver must use the same nonce size. Query with itb.GetNonceBits().

Barrier Fill (CSPRNG Margin)

itb.SetBarrierFill(4) // side += 4 instead of default side += 1

Controls the CSPRNG fill margin added to the container side dimension. The construction guarantees that every container has strictly more pixel capacity than the payload requires — the excess capacity is filled with crypto/rand data encrypted by dataSeed. This CSPRNG residue is indistinguishable from encrypted plaintext and provides information-theoretic ambiguity within the data channel (Proof 10).

Valid values: 1, 2, 4, 8, 16, 32. Default: 1. Panics on invalid input. Thread-safe (atomic). Query with itb.GetBarrierFill().

Why this matters after CCA. Under CCA (MAC + Reveal), the attacker identifies and removes noise bits (12.5% of container), bypassing mechanism 1 (noise absorption). But CSPRNG fill bytes remain in the data bit positions — encrypted identically to plaintext by dataSeed (rotation + XOR). COBS decoding stops at the 0x00 null terminator and never reaches the fill region, so the fill content is never constrained by the plaintext structure. The attacker cannot distinguish encrypted plaintext from encrypted CSPRNG fill without the correct dataSeed. Although CCA reveals noise bit positions (bypassing the noise-position uncertainty of mechanism 1), CSPRNG residue in data positions provides independent information-theoretic ambiguity that persists regardless of CCA.

The rotation barrier (7^P from Proof 4) remains complemented by this reduced information-theoretic barrier from CSPRNG fill. Three layers operate in every scenario:

Layer Core ITB After CCA (MAC + Reveal)
Noise absorption (mechanism 1) Full (8 noise bits/pixel) Partial — noise bits removed, CSPRNG fill in data positions survives
Encoding ambiguity (mechanism 2) 56^P 7^P (rotation only)
Brute-force cost P × 2^(2×keyBits) P × 2^keyBits

Asymmetric property. The receiver does not need the same SetBarrierFill value as the sender. Encrypt writes the container dimensions (W×H) into the header; Decrypt reads W×H from the header and processes whatever pixels are present. A larger fill margin on the sender side increases CSPRNG residue without requiring any configuration change on the receiver. This confirms the configurable nature of the information-theoretic barrier — the sender can independently tune the CSPRNG fill margin.

Hash Function Selection

ITB accepts pluggable hash functions at three widths. Requirements: the hash must process all input bytes with non-invertible, non-affine, avalanche mixing that survives the ChainHash XOR-chain. PRF required. Under PRF assumption, Full KPA resistance is 3-factor: PRF non-invertibility, independent startSeed, and per-pixel 1:1 ambiguity — all combine conjunctively. gcd(7,8)=1 byte-splitting is a 4th factor effective only under Partial KPA. Note: complete PRF inversion would collapse the architectural layers via seed recovery; the multi-factor property protects against partial PRF weakness, not total failure.

All nine primitives are PRF-grade and accept ITB key sizes up to 2048 bits (itb.MaxKeyBits); the per-width minimum is 512 bits and the bit count must be a multiple of the hash's native state width (128 / 256 / 512). The Public Pair API column lists the hashes.<Primitive>Pair() factory which returns the (single, batched) closure pair; the batched arm wires the ZMM-batched chain-absorb dispatch through Seed.BatchHash automatically.

Hash Type ASM Acceleration Public Pair API Upstream Library
Areion-SoEM-256 HashFunc256 VAES + AVX-512 ZMM (4-lane chain-absorb) · VAES + AVX-2 YMM fallback · AES-NI scalar hashes.Areion256Pair() github.com/jedisct1/go-aes
Areion-SoEM-512 HashFunc512 VAES + AVX-512 ZMM (4-lane chain-absorb) · VAES + AVX-2 YMM fallback · AES-NI scalar hashes.Areion512Pair() github.com/jedisct1/go-aes
SipHash-2-4 HashFunc128 AVX-512 ZMM ARX (VPADDQ / VPXORQ / VPROLQ, 4-lane) hashes.SipHash24Pair() github.com/dchest/siphash
AES-CMAC HashFunc128 VAES + AVX-512 ZMM (4-lane CBC-MAC) · AES-NI scalar hashes.AESCMACPair() crypto/aes (stdlib)
BLAKE2b-512 HashFunc512 AVX-512 ZMM ARX (VPADDQ / VPXORQ / VPRORQ, 4-lane) hashes.BLAKE2b512Pair() golang.org/x/crypto/blake2b
BLAKE2b-256 HashFunc256 AVX-512 ZMM ARX (VPADDQ / VPXORQ / VPRORQ, 4-lane) hashes.BLAKE2b256Pair() golang.org/x/crypto/blake2b
BLAKE2s HashFunc256 AVX-512 ZMM ARX (VPADDD / VPXORD / VPRORD, 4-lane) hashes.BLAKE2s256Pair() golang.org/x/crypto/blake2s
BLAKE3 HashFunc256 AVX-512 ZMM ARX (VPADDD / VPXORD / VPRORD, 4-lane keyed-mode) hashes.BLAKE3256Pair() github.com/zeebo/blake3
ChaCha20 HashFunc256 AVX-512 ZMM ARX (VPADDD / VPXORD / VPROLD, 4-lane) hashes.ChaCha20256Pair() golang.org/x/crypto/chacha20

Choosing the Right Hash Width

The effective key size is determined by the seed input width of the hash function — not its output width. This is a critical distinction:

Effective max key = min(keyBits, seedInputWidth × numRounds)

Why Wider Hash = Faster with Wider MITM Bottleneck

With a 512-bit key (8 components), ChainHash processes components in groups matching the hash width:

Hash width Components/round Rounds Hash calls/pixel
128-bit 2 4 4
256-bit 4 2 2
512-bit 8 1 1

All 8 components are consumed in every case — no key material is skipped. A 256-bit hash simply processes 4 components per call instead of 1.

Faster: each hash call has overhead (state initialization, finalization). For heavy hash functions (BLAKE3: ~300ns/call, BLAKE2b: ~200ns/call), fewer calls = proportionally faster.

Wider MITM bottleneck: the wider intermediate state makes meet-in-the-middle attacks harder. With 256-bit state, an attacker must enumerate 2^256 possible intermediate values (vs 2^128 for a 128-bit hash). Additionally, fewer chain rounds means fewer potential split points for the attacker.

Bottom line: prefer the widest available PRF variant — it's both faster and provides a wider MITM bottleneck.

Hash Function Wrappers

// 128-bit: HashFunc128 = func(data []byte, seed0, seed1 uint64) (lo, hi uint64)
// SipHash-2-4 (PRF) — see Optimized Hash Wrappers above
// AES-NI cached (PRF, hardware-accelerated) — see Optimized Hash Wrappers above

// 256-bit: HashFunc256 = func(data []byte, seed [4]uint64) [4]uint64
// BLAKE3 keyed cached (PRF, SIMD) — see Optimized Hash Wrappers above

// 512-bit: HashFunc512 = func(data []byte, seed [8]uint64) [8]uint64
// BLAKE2b-512 keyed cached (PRF, native 512-bit) — see Optimized Hash Wrappers above

Key Size Selection

// 128-bit hash: up to 1024-bit keys
ns128, _ := itb.NewSeed128(1024, hashes.SipHash24())
ds128, _ := itb.NewSeed128(1024, hashes.SipHash24())
ss128, _ := itb.NewSeed128(1024, hashes.SipHash24())

// 256-bit hash: up to 2048-bit keys
ns256, _ := itb.NewSeed256(2048, hashes.BLAKE3())
ds256, _ := itb.NewSeed256(2048, hashes.BLAKE3())
ss256, _ := itb.NewSeed256(2048, hashes.BLAKE3())

// 512-bit hash: up to 2048-bit keys
ns512, _ := itb.NewSeed512(2048, hashes.BLAKE2b512())
ds512, _ := itb.NewSeed512(2048, hashes.BLAKE2b512())
ss512, _ := itb.NewSeed512(2048, hashes.BLAKE2b512())

Seed Alignment Requirements

Seed Type Bits Range Bits Alignment Components Components Alignment
Seed128 [512, 2048] multiple of 128 [8, 32] ×2
Seed256 [512, 2048] multiple of 256 [8, 32] multiple of 4
Seed512 (512-bit) [512, 2048] multiple of 512 [8, 32] multiple of 8

Minimum Container Size

Minimum container size depends on the API mode. Encrypt/Stream uses ceil(keyBits / log₂(56)) pixels, ensuring encoding ambiguity (56^P) exceeds the key space. Auth uses ceil(keyBits / log₂(7)) pixels, ensuring CCA ambiguity (7^P) exceeds the key space:

Key Size Mode Min Pixels → Container Noise Barrier
1024 bits Encrypt/Stream 177 → 196 (14×14) 2^1568 ≥ 2^1024
1024 bits Auth 365 → 400 (20×20) 2^3200 ≥ 2^1024
2048 bits Encrypt/Stream 353 → 361 (19×19) 2^2888 ≥ 2^2048
2048 bits Auth 730 → 784 (28×28) 2^6272 ≥ 2^2048

Output Format

Offset  Size     Content
0       N        Nonce (crypto/rand, public; N = 16/32/64 bytes for 128/256/512-bit nonce)
N       2        Width (uint16 big-endian)
N+2     2        Height (uint16 big-endian)
N+4     W×H×8    Raw RGBWYOPA pixel data with embedded encrypted payload

Default nonce size is 128-bit (16 bytes). Configurable to 256-bit (32 bytes) or 512-bit (64 bytes) via SetNonceBits. The output format is identical across all three hash width variants.

Security Summary

Property ITB
Key space Up to 2^2048
Grover resistance √P × 2^keyBits (Core/Silent Drop) to √P × 2^(keyBits/2) (MAC + Reveal)
Plausible deniability ✓ All modes (wrong seed → garbage indistinguishable from valid plaintext)
Encoding ambiguity ✓ All modes (7^P unverifiable rotation combinations, survives CCA; CSPRNG residue adds independent ambiguity in data positions, Proof 10)
Triple-seed isolation ✓ All modes (noiseSeed / dataSeed / startSeed independent; CCA leaks noiseSeed only)
Oracle-free deniability ✓ Core ITB / MAC + Silent Drop; MAC + Reveal has CCA oracle limited to noise positions
Known-plaintext resistance 3-factor under PRF assumption for Full KPA: PRF non-invertibility + independent startSeed + 7-rotation × 8-noisePos per-pixel ambiguity at signal/noise 1:1. gcd(7,8) byte-splitting is a 4th factor effective only under Partial KPA (see Proof 4a)
Chosen-plaintext resistance Independent maps
Noise absorption ✓ Core ITB / MAC + Silent Drop; bypassed via CCA in MAC + Reveal (CSPRNG residue in data positions survives, Proof 10)
Noise barrier (min container) 2^1568 (1024-bit, P=196) to 2^2888 (2048-bit, P=361)
Hash function requirement PRF required; PRF and barrier are complementary — neither sufficient alone (see Proof 4a)
Nonce reuse protection 128/256/512-bit per-message nonce (default 128-bit)
Nonce misuse resistance Local only: at most 2–3 colliding messages theoretically affected. In practice ITB's per-encryption noise + rotation + channelXOR mean C1 ⊕ C2 does NOT reduce to plaintext_1 ⊕ plaintext_2 as in a stream cipher — plaintext recovery requires the full demasker pipeline whose output is the hash stream, not plaintext bits (see ITB.md §8). Seeds remain secret (PRF non-invertibility), future messages safe, no key rotation required. Single collision too few observations for Simon / structural / quantum algebraic attacks. Unlike AES-GCM where nonce reuse leaks H and enables forgery until key rotation (global catastrophe)
Storage overhead 1.14× (56 data bits per 64-bit pixel)

Integrity (MAC-Inside-Encrypt)

The core construction provides confidentiality only. For integrity protection against bit-flipping attacks, use the MAC-Inside-Encrypt pattern — the MAC is encrypted inside the container, preserving oracle-free deniability:

// 128-bit variant
encrypted, err := itb.EncryptAuthenticated128(ns128, ds128, ss128, plaintext, myMACFunc)
original, err = itb.DecryptAuthenticated128(ns128, ds128, ss128, encrypted, myMACFunc)

// 256-bit variant
encrypted, err = itb.EncryptAuthenticated256(ns256, ds256, ss256, plaintext, myMACFunc)
original, err = itb.DecryptAuthenticated256(ns256, ds256, ss256, encrypted, myMACFunc)

// 512-bit variant
encrypted, err = itb.EncryptAuthenticated512(ns512, ds512, ss512, plaintext, myMACFunc)
original, err = itb.DecryptAuthenticated512(ns512, ds512, ss512, encrypted, myMACFunc)

Important: never place a MAC outside the encrypted container in cleartext — this creates a verification oracle that breaks deniability.

Triple-Seed Isolation

All three seeds must be distinct pointers — passing the same seed as multiple parameters returns an error:

// This will fail:
encrypted, err := itb.Encrypt128(seed, seed, seed, data)
// Error: "itb: all three seeds must be different (triple-seed isolation)"

// Correct usage: three independent seeds
encrypted, err := itb.Encrypt128(noiseSeed, dataSeed, startSeed, data)

Formal Security Model

A simulation-based proof is a purely mathematical construction: "for every adversary A in the real world, there exists a simulator S in the ideal world such that the outputs of A and S are indistinguishable." This is proven logically, not computationally. It is independent of hardware, logic system, or computational model.

ITB does not fit cleanly into the standard binary security model:

  • Standard model: the adversary either distinguishes (break) or does not (secure). Binary.
  • ITB: the adversary always receives output. The output is always "valid." There is no point where the system returns accept/reject. Instead, the result is a spectrum of plausibility — every key produces output, and there is no way to rank candidates without external context.

The semantics of decryption are ternary:

  1. Correct key → correct plaintext
  2. Wrong key → garbage indistinguishable from plaintext
  3. Observer → cannot determine which of the two cases is present

Possible formalization paths:

  • Indistinguishability-based definitions (standard in cryptography, binary logic — sufficient)
  • Simulation-based proof with an ideal functionality that always returns random bytes (this is the "ideal world" of ITB — the real-world output is indistinguishable from random)
  • Quantitative information flow (how many bits leak — the per-byte barrier shows 0 bits leaked per observation)

All three approaches use standard mathematics. The formal relationship between ITB's Ambiguity-Based Security and Shannon's framework remains an open research question (see SCIENCE.md §7).

See Also

  • ITB.md — How the barrier works (accessible explanation)
  • ITB3.md — Triple Ouroboros (7-seed variant, 3× security)
  • FEATURES.md — Complete feature list and security properties
  • PROOFS.md — Formal security proofs
  • SCIENCE.md — Scientific analysis and formal security arguments
  • SECURITY.md — Security reference tables
  • HWTHREATS.md — Hardware-level threat analysis (Spectre, Meltdown, Rowhammer, etc.)
  • REDTEAM.md — Empirical red-team validation (12-primitive hash matrix, multiple statistical / structural distinguishers, 2×2 Ouroboros × BarrierFill matrix)
  • hashes/CONSTRUCTIONS.md — Per-primitive construction descriptions (how each registry name wraps its underlying RFC / NIST primitive, where the wrappers diverge from the canonical specification, and why)

License

MIT — see LICENSE.

About

Experimental symmetric cipher construction

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors