easy

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 20, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package easy — streaming surface and bindings asymmetry.

Encryptor exposes two parallel streaming surfaces. The callback-driven family (Encryptor.EncryptStream / Encryptor.DecryptStream and the authenticated counterparts Encryptor.EncryptStreamAuth / Encryptor.DecryptStreamAuth) invokes a ChunkFunc once per output chunk in stream order and is the natural fit when the caller already holds the full plaintext (or full ciphertext) in memory and prefers per-chunk control over emission. The IO-Driven family (Encryptor.EncryptStreamIO / Encryptor.DecryptStreamIO and the authenticated counterparts Encryptor.EncryptStreamAuthIO / Encryptor.DecryptStreamAuthIO) consumes io.Reader / writes io.Writer and drives the read/write loop internally — suited to inputs that exceed RAM. The two surfaces produce identical on-wire bytes for matching configurations.

Streaming AEAD per-chunk primitives. Encryptor.EncryptStreamAuthenticated and Encryptor.DecryptStreamAuthenticated are the per-chunk primitives at the Easy Mode surface. The caller supplies the 32-byte streamID (CSPRNG-fresh per stream, written once as the wire prefix preceding chunk 0), the running cumulative pixel offset of all preceding chunks, and the finalFlag (true on the terminating chunk only). Each call returns one self-contained authenticated wire chunk. Encryptor.HeaderSize and Encryptor.ParseChunkLen expose the per-instance header parsers used to walk a concatenated transcript without reading whole chunks into memory.

Bindings asymmetry. The Encryptor.EncryptStreamIO / Encryptor.DecryptStreamIO methods drive the No-MAC plain-stream loop internally over io.Reader / io.Writer. The official language bindings expose the No-MAC stream surface as per-chunk free functions only and let the caller drive the read/write loop. Both patterns produce identical on-wire bytes; the IO-method form is a Go-side convenience.

Package easy provides a high-level Encryptor / Decryptor object on top of the lower-level [itb.Encrypt{128,256,512}Cfg] / friends API. One constructor call (New or New3) replaces the existing 7-line setup ceremony — hash factory, three (or seven) seeds, MAC closure, container-config wiring — and returns an Encryptor that owns its own per-instance configuration so two encryptors with different settings can run in parallel goroutines without cross- contamination.

New / New3 bind one PRF primitive across every seed slot of the resulting Encryptor. NewMixed / NewMixed3 take a per-slot primitive spec instead, allowing the noise / data / start (and optional dedicated lockSeed) seed slots to use different PRF primitives within the same native hash width; width mismatches are rejected at construction with ErrEasyMixedWidth. The MAC primitive remains one per encryptor on both paths.

Concurrency. Distinct Encryptor values run in parallel goroutines as documented above; a single Encryptor is NOT safe for concurrent use from multiple goroutines (cipher methods, setters, Encryptor.Close, and Encryptor.Import all mutate per-instance state without locking — see Encryptor for the full contract). Callers needing to share one Encryptor across goroutines wrap every method call in a sync.Mutex. The low-level free functions in the parent package (github.com/everanium/itb.Encrypt128Cfg / github.com/everanium/itb.EncryptAuthenticated128Cfg and the 256 / 512 width counterparts) are thread-safe under concurrent invocation on the same seeds.

Index

Constants

View Source
const MixedPrimitive = "mixed"

MixedPrimitive is the canonical [Encryptor.Primitive] string for encryptors built via NewMixed / NewMixed3. Single-primitive encryptors built via New / New3 carry the primitive name directly in this field; mixed-mode encryptors set it to the "mixed" literal and expose the per-slot primitive through Encryptor.PrimitiveAt.

Variables

View Source
var ErrBadKeyBits = errors.New("itb/easy: invalid key_bits in state blob")

ErrBadKeyBits indicates the state blob's key_bits value is outside the supported {512, 1024, 2048} set or is not an integer multiple of the primitive's native width.

View Source
var ErrClosed = errors.New("itb/easy: encryptor is closed")

ErrClosed indicates the encryptor's state has been zeroed by Encryptor.Close; subsequent method calls on the same instance return this error.

View Source
var ErrEasyMixedWidth = errors.New("itb/easy: mixed-mode primitives must share the same native hash width")

ErrEasyMixedWidth indicates that one or more primitive names in a MixedSpec / MixedSpec3 resolve to a different native hash width than the noiseSeed primitive. The Go type system requires every seed slot in one encryptor to share the same width — mixing widths is rejected at construction time before any seed is allocated.

View Source
var ErrLockSeedAfterEncrypt = errors.New("itb/easy: SetLockSeed after first Encrypt is not allowed")

ErrLockSeedAfterEncrypt indicates Encryptor.SetLockSeed was called after the encryptor produced its first ciphertext. The bit-permutation derivation path cannot change mid-session without breaking decryptability of previously-emitted ciphertext, so the switch is rejected.

View Source
var ErrMalformed = errors.New("itb/easy: malformed state blob")

ErrMalformed indicates the state blob passed to Encryptor.Import is structurally invalid — JSON parse failure, unknown kind tag, unsupported mode value, non-canonical lock_seed encoding, or any other shape the v1 decoder rejects before field-level validation.

View Source
var ErrUnknownMAC = errors.New("itb/easy: unknown MAC in state blob")

ErrUnknownMAC indicates the state blob names a MAC not present in the local macs.Registry.

View Source
var ErrUnknownPrimitive = errors.New("itb/easy: unknown primitive in state blob")

ErrUnknownPrimitive indicates the state blob names a hash primitive not present in the local hashes.Registry.

View Source
var ErrVersionTooNew = errors.New("itb/easy: state blob version too new")

ErrVersionTooNew indicates the state blob carries a version number greater than the highest version this build understands. Strict- fail is the correct posture for a cipher state blob — silent feature loss on a too-new blob risks subtle mis-decryption.

Functions

func PeekConfig

func PeekConfig(blob []byte) (primitive string, keyBits, mode int, mac string)

PeekConfig extracts (primitive, key_bits, mode, mac) from a serialized state blob without performing full validation. Useful for callers that want to inspect a saved blob's metadata before constructing a matching encryptor.

Panics on JSON parse failure, kind mismatch, version too new, or unknown mode value — same reasoning as the constructor panic policy: callers cannot meaningfully recover from a malformed blob.

func SetGCPercent

func SetGCPercent(pct int) int

SetGCPercent configures the Go runtime's GC trigger percentage. The default is 100 (GC fires at +100% heap growth); lower values trigger GC more aggressively. Pass -1 (or any negative value) to query the current value without changing it; the previous value is returned. Setter calls override any ITB_GOGC env var set at libitb load time.

func SetMemoryLimit

func SetMemoryLimit(limit int64) int64

SetMemoryLimit configures the Go runtime's heap-size soft limit (bytes). Pass -1 (or any negative value) to query the current limit without changing it; the previous limit is returned. Setter calls override any ITB_GOMEMLIMIT env var set at libitb load time.

Types

type ChunkFunc

type ChunkFunc func(chunk []byte) error

ChunkFunc is the per-chunk callback driven by Encryptor.EncryptStream and Encryptor.DecryptStream. The encryptor invokes ChunkFunc once per output chunk in stream order; returning a non-nil error from the callback aborts the stream and propagates the error to the caller.

type Encryptor

type Encryptor struct {
	// Primitive is the canonical [hashes.Registry] name the encryptor
	// is bound to.
	Primitive string

	// KeyBits is the per-seed key width in bits — one of 256, 512,
	// 1024, 2048. Must be an integer multiple of the primitive's
	// native hash width.
	KeyBits int

	// Mode selects Single Ouroboros (1, 3 seeds) or Triple Ouroboros
	// (3, 7 seeds). The integer encoding mirrors the Encrypt /
	// Encrypt3x distinction at the low-level API.
	Mode int

	// MACName is the canonical [macs.Registry] name the bound MAC
	// closure was derived from.
	MACName string
	// contains filtered or unexported fields
}

Encryptor is the high-level encrypt / decrypt object returned by New and New3. It owns a per-instance config snapshot taken at construction time, fixed PRF keys and seed components for each seed slot, a MAC closure bound to a fixed MAC key, and an optional dedicated lockSeed when LockSeed is active.

The four exported fields (Primitive, KeyBits, Mode, MACName) are read-only after construction. Mutating them directly produces undefined behaviour; reads are safe. Subsequent configuration changes go through the Encryptor.SetNonceBits, Encryptor.SetBarrierFill, Encryptor.SetBitSoup, Encryptor.SetLockSoup, Encryptor.SetLockSeed, and Encryptor.SetChunkSize methods, which mutate the encryptor's own config copy without touching process globals or other encryptors.

Concurrency. A single Encryptor is NOT safe for concurrent use from multiple goroutines: cipher methods (Encryptor.Encrypt / Encryptor.Decrypt / Encryptor.EncryptAuth / Encryptor.DecryptAuth) write the firstEncryptCalled flag and allocate the output buffer through the shared cgo handle table, per-instance setters mutate cfg fields and the *Explicit flags without locking, and Encryptor.Close / Encryptor.Import mutate the closed flag and seed material. Sharing one Encryptor across goroutines requires external synchronisation (a sync.Mutex held for the duration of every cipher call, or a single-owner channel pattern). Distinct Encryptor values, each owned by one goroutine, run independently against the libitb worker pool — that is the supported parallelism model. The low-level free functions github.com/everanium/itb.Encrypt128Cfg / github.com/everanium/itb.EncryptAuthenticated128Cfg (and the 256 / 512 width counterparts) allocate output per call, take read-only Seed pointers, and are safe under concurrent invocation on the same seeds; the cfg pointer itself remains shared, so concurrent setter mutations on a Config that other goroutines are reading is the caller's responsibility to serialise.

func New

func New(args ...any) *Encryptor

New constructs an Encryptor configured for Single Ouroboros (3 seeds — noise, data, start). args may include any of:

  • One string matching hashes.Registry — selects the PRF primitive; default "areion512".
  • One string matching macs.Registry — selects the MAC; default "hmac-blake3".
  • One int — selects key_bits; default 1024.

Argument order is irrelevant; type-dispatch resolves each value to its role. Duplicates of the same kind, unknown names, unsupported argument types, key_bits outside {512, 1024, 2048} or not divisible by the primitive's native width all panic — security parameters are not recoverable, and surfacing them as Go errors invites code that ignores the value.

crypto/rand failure during PRF / seed / MAC key generation is also a panic with the standard "itb: crypto/rand: ..." message — the same convention as the existing low-level constructors.

The returned Encryptor's exported fields (Primitive, KeyBits, Mode, MACName) are read-only after construction; configuration changes go through the per-encryptor setters.

func New3

func New3(args ...any) *Encryptor

New3 constructs an Encryptor configured for Triple Ouroboros (7 seeds — noise plus three pairs of (data, start)). Variadic argument shape matches New.

func NewMixed

func NewMixed(spec MixedSpec) *Encryptor

NewMixed constructs a Single-Ouroboros Encryptor with per-slot PRF primitive selection. Allows the noise / data / start seeds to run different PRFs within the same native hash width — the freedom the lower-level itb.Encrypt256 path already supports, surfaced through Easy Mode without forcing the caller off the high-level API.

The optional dedicated lockSeed (PrimitiveL non-empty) is allocated as a 4th seed slot under its own primitive choice; BitSoup / LockSoup are auto-coupled on the on-direction and the noiseSeed [itb.Seed{N}.AttachLockSeed] mutator is invoked so the bit-permutation overlay routes through the dedicated seed immediately. Empty PrimitiveL leaves the encryptor in the same 3-slot state New would produce.

Validation panics on the same conditions as New (unknown primitive / MAC, invalid KeyBits, KeyBits not divisible by primitive width) plus ErrEasyMixedWidth when slot primitives disagree on native width. crypto/rand failures during PRF / seed / MAC key generation panic with the standard "itb/easy: crypto/rand: ..." prefix.

func NewMixed3

func NewMixed3(spec MixedSpec3) *Encryptor

NewMixed3 constructs a Triple-Ouroboros Encryptor with per-slot PRF primitive selection. See NewMixed for the construction contract; the slot count grows from 3 to 7 (1 noise + 3 data + 3 start) plus the optional dedicated lockSeed slot.

func (*Encryptor) Close

func (e *Encryptor) Close() error

Close zeroes the encryptor's PRF keys, MAC key, and seed components, drops the bound MAC closure and any dedicated LockSeedHandle, and marks the encryptor as closed. Subsequent method calls on this instance panic with ErrClosed.

Idempotent — multiple Close calls return nil without panic.

Returns error to compose with `defer enc.Close()` and errors.Join; current implementation never returns a non-nil error (the close path has no I/O and no failure modes), but the signature reserves the slot for future extensions.

func (*Encryptor) Decrypt

func (e *Encryptor) Decrypt(ciphertext []byte) ([]byte, error)

Decrypt decrypts ciphertext produced by Encryptor.Encrypt using the encryptor's per-instance Config snapshot. Plain mode — never performs MAC verification; for authenticated decryption use Encryptor.DecryptAuth.

Panics with ErrClosed when called after Encryptor.Close. Returns an error only on structural issues (header parse, dimension validation); a wrong-seed input produces random-looking plaintext rather than an error — non-Auth mode has no failure signal by design.

func (*Encryptor) DecryptAuth

func (e *Encryptor) DecryptAuth(ciphertext []byte) ([]byte, error)

DecryptAuth verifies and decrypts ciphertext produced by Encryptor.EncryptAuth. The MAC tag is checked against the encryptor's bound MAC closure; mismatch yields the standard "MAC verification failed" error from the underlying [itb.DecryptAuthenticated{N}] / [itb.DecryptAuthenticated3x{N}] entry point.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) DecryptStream

func (e *Encryptor) DecryptStream(ciphertext []byte, emit ChunkFunc) error

DecryptStream walks a concatenated stream of ciphertext chunks produced by Encryptor.EncryptStream, invoking emit once per recovered plaintext chunk in stream order. The chunk-size override does not apply on the decrypt side — chunk extents are recovered from the wire-format header per chunk.

Panics with ErrClosed when called after Encryptor.Close. Returns the first non-nil error from the chunk emitter or from the underlying [itb.DecryptStream{N}Cfg] / [itb.DecryptStream3x{N}Cfg] entry point. Wrong-seed input on non-authenticated streams produces random-looking plaintext per chunk rather than an error — non-Auth mode has no failure signal by design.

func (*Encryptor) DecryptStreamAuth

func (e *Encryptor) DecryptStreamAuth(ciphertext []byte, emit ChunkFunc) error

DecryptStreamAuth walks a Streaming AEAD transcript produced by Encryptor.EncryptStreamAuth, reading the leading 32-byte stream anchor and verifying every following chunk under the encryptor's bound MAC closure with the running cumulative pixel offset. Recovered plaintext is delivered through emit once per chunk in stream order. Returns itb.ErrStreamTruncated when the transcript exhausts without observing a chunk whose finalFlag is true and itb.ErrStreamAfterFinal when additional chunk bytes follow the terminator.

Panics with ErrClosed when called after Encryptor.Close. Returns the first non-nil error from the chunk emitter, a MAC verification failure, or any structural error reported by the underlying [itb.DecryptStreamAuth{N}Cfg] / [itb.DecryptStreamAuth3x{N}Cfg] entry point.

func (*Encryptor) DecryptStreamAuthIO

func (e *Encryptor) DecryptStreamAuthIO(src io.Reader, dst io.Writer) error

DecryptStreamAuthIO decrypts a Streaming AEAD transcript driven by io.Reader / io.Writer. Reads the leading 32-byte stream anchor from src, walks the remaining bytes one chunk at a time using the per-instance header size, dispatches each chunk through Encryptor.DecryptStreamAuthenticated with the running cumulative pixel offset, and writes recovered plaintext to dst. Returns itb.ErrStreamTruncated when the transcript exhausts without a terminating chunk and itb.ErrStreamAfterFinal when chunks follow a terminator.

Panics with ErrClosed when called after Encryptor.Close. Returns the first non-nil error from the underlying per-chunk Encryptor.DecryptStreamAuthenticated call, the writer's Write, or the reader's Read.

func (*Encryptor) DecryptStreamAuthenticated

func (e *Encryptor) DecryptStreamAuthenticated(
	chunkData []byte,
	streamID [32]byte,
	cumulativePixelOffset uint64,
) (plaintext []byte, finalFlag bool, err error)

DecryptStreamAuthenticated decrypts a single Streaming AEAD chunk under the encryptor's bound seeds + MAC. The caller supplies the streamID (extracted from the 32-byte stream prefix at the start of the wire transcript) and the running cumulativePixelOffset (recomputed from the W*H header of every preceding chunk). The recovered finalFlag indicates whether this chunk is the terminator (true) or a non-terminal chunk (false).

Panics with ErrClosed when called after Encryptor.Close. Returns an error on MAC verification failure or the same failure paths as [itb.DecryptStreamAuthenticated{N}] / [itb.DecryptStreamAuthenticated3x{N}].

func (*Encryptor) DecryptStreamIO

func (e *Encryptor) DecryptStreamIO(src io.Reader, dst io.Writer) error

DecryptStreamIO decrypts a plain stream produced by Encryptor.EncryptStreamIO (or any wire-format-compatible producer such as Encryptor.EncryptStream / the top-level itb.EncryptStream family). Reads one chunk at a time using the per-instance header size, dispatches the chunk through the matching width-suffixed per-chunk decrypt path, and writes the recovered plaintext to dst.

Wrong-seed input on plain (non-authenticated) streams produces random-looking plaintext per chunk rather than an error — plain mode has no failure signal by design.

Panics with ErrClosed when called after Encryptor.Close. Returns the first non-nil error from the underlying per-chunk Encryptor.Decrypt call, the writer's Write, or the reader's Read.

func (*Encryptor) Encrypt

func (e *Encryptor) Encrypt(plaintext []byte) ([]byte, error)

Encrypt encrypts plaintext using the configured primitive / key_bits / Mode and the encryptor's per-instance Config snapshot. Plain mode — does NOT compute or attach a MAC tag; for authenticated encryption use Encryptor.EncryptAuth.

Panics with ErrClosed when called after Encryptor.Close. Returns an error for all other failure paths (CSPRNG failure, data too large, internal sizing error) — same error shape as the underlying itb.Encrypt128 / itb.Encrypt256 / itb.Encrypt512 / [itb.Encrypt3x{N}] entry points.

Marks the encryptor as having produced ciphertext on the first successful call, after which Encryptor.SetLockSeed is rejected (the bit-permutation derivation path cannot change mid-session without breaking decryptability of pre-switch ciphertext).

func (*Encryptor) EncryptAuth

func (e *Encryptor) EncryptAuth(plaintext []byte) ([]byte, error)

EncryptAuth encrypts plaintext and attaches a MAC tag using the encryptor's per-instance Config snapshot and the MAC closure bound at construction. Authenticated mode — produces a ciphertext the receiver must validate via Encryptor.DecryptAuth before trusting the recovered plaintext.

Panics with ErrClosed when called after Encryptor.Close. Returns an error for the same failure paths as itb.EncryptAuthenticated128 / itb.EncryptAuthenticated256 / itb.EncryptAuthenticated512 / [itb.EncryptAuthenticated3x{N}].

func (*Encryptor) EncryptStream

func (e *Encryptor) EncryptStream(plaintext []byte, emit ChunkFunc) error

EncryptStream encrypts plaintext in chunks, invoking emit once per output chunk in stream order. The chunk-size override is the encryptor's chunk field (set via Encryptor.SetChunkSize; 0 = auto-detect via itb.ChunkSize).

Panics with ErrClosed when called after Encryptor.Close. Returns the first non-nil error from the chunk emitter or from the underlying [itb.EncryptStream{N}Cfg] / [itb.EncryptStream3x{N}Cfg] entry point.

func (*Encryptor) EncryptStreamAuth

func (e *Encryptor) EncryptStreamAuth(plaintext []byte, emit ChunkFunc) error

EncryptStreamAuth encrypts plaintext as a Streaming AEAD transcript under the encryptor's bound seeds + MAC. The helper generates a fresh 32-byte stream anchor at stream start, emits it as the first wire chunk through emit, then walks plaintext in chunks of the encryptor's chunk override (set via Encryptor.SetChunkSize; 0 = auto-detect via itb.ChunkSize) calling Encryptor.EncryptStreamAuthenticated per chunk with the running cumulative pixel offset and finalFlag = true on the last chunk.

Empty plaintext is permitted: emit receives the 32-byte stream prefix followed by a single terminating chunk built from a 0-byte payload with finalFlag = true.

Panics with ErrClosed when called after Encryptor.Close. Returns the first non-nil error from the chunk emitter or from the underlying [itb.EncryptStreamAuth{N}Cfg] / [itb.EncryptStreamAuth3x{N}Cfg] entry point.

func (*Encryptor) EncryptStreamAuthIO

func (e *Encryptor) EncryptStreamAuthIO(src io.Reader, dst io.Writer, chunkSize int) error

EncryptStreamAuthIO encrypts a Streaming AEAD transcript driven by io.Reader / io.Writer. The helper generates a fresh 32-byte stream anchor at stream start, writes it as the wire prefix, then drains src in chunkSize-byte windows and emits each per-chunk wire payload through dst. The terminating chunk carries finalFlag = true; an empty src draws and emits the streamID prefix followed by a single zero-length terminating chunk.

chunkSize must be > 0; a zero or negative value falls back to the encryptor's Encryptor.SetChunkSize override (or itb.DefaultChunkSize when unset). Plaintext is read from src in streaming windows of the resolved chunk size, so callers can process inputs that exceed available RAM.

Panics with ErrClosed when called after Encryptor.Close. Returns the first non-nil error from the underlying per-chunk Encryptor.EncryptStreamAuthenticated call, the writer's Write, or the reader's Read.

func (*Encryptor) EncryptStreamAuthenticated

func (e *Encryptor) EncryptStreamAuthenticated(
	plaintext []byte,
	streamID [32]byte,
	cumulativePixelOffset uint64,
	finalFlag bool,
) ([]byte, error)

EncryptStreamAuthenticated encrypts a single Streaming AEAD chunk under the encryptor's bound seeds + MAC, with the streaming binding components (streamID, cumulativePixelOffset, finalFlag) included in the per-chunk MAC input. The returned chunk is one self-contained authenticated wire chunk; the caller composes streams by writing a 32-byte CSPRNG streamID prefix once at stream start, then invoking this method per chunk with the running cumulativePixelOffset and finalFlag = true on the terminating chunk only.

Panics with ErrClosed when called after Encryptor.Close. Returns an error for the same failure paths as itb.EncryptStreamAuthenticated128 / itb.EncryptStreamAuthenticated256 / itb.EncryptStreamAuthenticated512 / [itb.EncryptStreamAuthenticated3x{N}].

func (*Encryptor) EncryptStreamIO

func (e *Encryptor) EncryptStreamIO(src io.Reader, dst io.Writer, chunkSize int) error

EncryptStreamIO encrypts a plain (non-authenticated) stream driven by io.Reader / io.Writer. Reads up-to-chunkSize-byte windows from src, encrypts each non-empty window through the matching width-suffixed per-chunk path on the encryptor, and writes the resulting wire chunk to dst. Empty src input emits nothing — the underlying Single Message path rejects empty plaintext, and the streaming helper preserves that semantic by simply not emitting any chunk.

chunkSize must be > 0; a zero or negative value yields a BadInput- equivalent error before any byte is consumed from src. Plaintext is read in streaming windows of the supplied chunk size, so callers can process inputs that exceed available RAM.

Panics with ErrClosed when called after Encryptor.Close. Returns the first non-nil error from the underlying per-chunk Encryptor.Encrypt call, the writer's Write, or the reader's Read.

func (*Encryptor) Export

func (e *Encryptor) Export() []byte

Export returns the encryptor's full state as JSON-encoded bytes. The caller saves the bytes to disk / KMS / wire as it sees fit and later passes them back to Encryptor.Import on a fresh encryptor to reconstruct the exact state — same PRF fixed keys, same seed components, same MAC key, same dedicated lockSeed material if active.

Per-encryptor configuration knobs (NonceBits, BarrierFill, BitSoup, LockSoup) are NOT carried in the v1 blob — both sides communicate them via deployment config. LockSeed is carried because activating it changes the structural seed count.

Infallible — JSON marshal of a validated internal struct cannot fail under normal operation; a nil-receiver / closed-encryptor surface as a panic.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) HeaderSize

func (e *Encryptor) HeaderSize() int

HeaderSize returns the per-instance ciphertext-chunk header size in bytes — nonce + 2-byte width + 2-byte height. Tracks this encryptor's own Encryptor.NonceBits, NOT the process-wide itb.GetNonceBits reading.

Use this when slicing a chunk header off the front of a ciphertext stream produced by this encryptor or when sizing a tamper region for an authenticated-decrypt test. Callers that nibble through a ciphertext stream chunk-by-chunk instead of going through Encryptor.EncryptStream / Encryptor.DecryptStream pair this with Encryptor.ParseChunkLen to walk the wire format without touching the process-wide accessors.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) Import

func (e *Encryptor) Import(blobBytes []byte) error

Import consumes a JSON state blob produced by a prior Encryptor.Export call and replaces the receiver's PRF keys, seed components, MAC key, and (optionally) dedicated lockSeed material with the imported state. Returns nil on success or one of the package's sentinel errors / ErrMismatch on any validation failure; on error the encryptor's pre-Import state is unchanged.

The blob carries the authoritative LockSeed setting. The receiver's pre-Import LockSeed state is silently overridden — a blob with lock_seed:true elevates a default-LockSeed=0 receiver to LockSeed=1 (and the imported lockSeed material populates the 4th/8th seed slot); a blob without lock_seed demotes a pre-Import LockSeed=1 receiver to LockSeed=0 (and the receiver's pre-Import dedicated-lockSeed material is zeroed and discarded). The four other configuration dimensions (primitive, key_bits, mode, mac) reject on mismatch because the receiver's hash / MAC factories were bound at New / New3 time.

firstEncryptCalled is reset to false on every successful Import — the encryptor is conceptually reborn, so Encryptor.SetLockSeed is allowed again until the next first-Encrypt-on-this-state.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) IsMixed

func (e *Encryptor) IsMixed() bool

IsMixed reports whether the encryptor was constructed via NewMixed / NewMixed3 (per-slot primitive selection) or via New / New3 (single primitive across all slots).

Equivalent to checking [Encryptor.Primitive] == MixedPrimitive, surfaced as a typed predicate for code that prefers a boolean over a string comparison.

func (*Encryptor) MACKey

func (e *Encryptor) MACKey() []byte

MACKey returns a defensive copy of the encryptor's bound MAC fixed key. Mutating the returned slice does not affect the encryptor.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) NonceBits

func (e *Encryptor) NonceBits() int

NonceBits returns the nonce size in bits configured for this encryptor — either the value installed by the most recent Encryptor.SetNonceBits call, or the process-wide itb.GetNonceBits reading at construction time when no per-instance override has been issued.

The internal Config field cfg.NonceBits is unexported and stays that way — callers read the value through this getter, mirroring the read-only [Encryptor.Primitive] / [Encryptor.KeyBits] / [Encryptor.Mode] / [Encryptor.MACName] surface. Read-only access only; the exported field-level path through cfg would let a caller mutate cfg.LockSeedHandle / cfg.LockSeed directly and break the bit-permutation derivation invariants enforced by Encryptor.SetLockSeed.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) PRFKeys

func (e *Encryptor) PRFKeys() [][]byte

PRFKeys returns a defensive copy of the per-seed fixed PRF keys. One entry per seed slot in canonical order: Single = [noise, data, start]; Triple = [noise, data1, data2, data3, start1, start2, start3]; with the dedicated lockSeed appended at the end when Encryptor.SetLockSeed(1) is active.

Returns nil for siphash24 — the primitive has no fixed PRF key (its keying material is the per-call seed components themselves).

Mutating the returned slice does not affect the encryptor; each call allocates fresh copies.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) ParseChunkLen

func (e *Encryptor) ParseChunkLen(header []byte) (int, error)

ParseChunkLen reports the total wire length of one ciphertext chunk after inspecting only the fixed-size header at the front of the supplied buffer. Per-instance counterpart of itb.ParseChunkLen: consults Encryptor.NonceBits instead of the process-wide itb.GetNonceBits, so a chunk produced by this encryptor under a non-default nonce size is parsed correctly regardless of the global state.

Buffer convention identical to itb.ParseChunkLen: only the header bytes need be present; the body bytes do not. Returns an error on too-short buffer, zero dimensions, or width × height overflow against the container pixel cap.

Streaming consumers walk the wire format with the standard per-chunk loop:

header := make([]byte, enc.HeaderSize())
for {
    if _, err := io.ReadFull(in, header); err == io.EOF {
        return
    }
    chunkLen, err := enc.ParseChunkLen(header)
    if err != nil { return err }
    body := make([]byte, chunkLen-enc.HeaderSize())
    if _, err := io.ReadFull(in, body); err != nil { return err }
    chunk := append(header, body...)
    pt, err := enc.Decrypt(chunk)
    if err != nil { return err }
    out.Write(pt)
}

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) PrimitiveAt

func (e *Encryptor) PrimitiveAt(slot int) string

PrimitiveAt returns the canonical hashes.Registry name bound to the seed at the given slot index. Slot ordering is canonical across the package:

  • Single mode: 0 = noiseSeed, 1 = dataSeed, 2 = startSeed.
  • Triple mode: 0 = noiseSeed, 1..3 = dataSeed1..3, 4..6 = startSeed1..3.
  • Optional dedicated lockSeed (when active) sits at the last index — len(seeds)-1.

For encryptors built via New / New3 every slot returns the same name [Encryptor.Primitive] is bound to. For encryptors built via NewMixed / NewMixed3 each slot can carry an independently chosen primitive within the shared native hash width.

Out-of-range slot indices return the empty string. Closed encryptors panic with ErrClosed, matching the rest of the Encryptor surface.

func (*Encryptor) SeedComponents

func (e *Encryptor) SeedComponents() [][]uint64

SeedComponents returns a defensive copy of the per-seed component vectors. One entry per seed slot in canonical order matching Encryptor.PRFKeys; each inner slice has length key_bits / 64.

Mutating the returned slice does not affect the encryptor; each call allocates fresh copies.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) SetBarrierFill

func (e *Encryptor) SetBarrierFill(n int)

SetBarrierFill overrides the CSPRNG barrier-fill margin for this encryptor. Valid values: 1, 2, 4, 8, 16, 32. Panics on invalid input — barrier misconfiguration is a security-critical bug.

Mutates only the encryptor's own itb.Config copy. Asymmetric: the receiver does not need the same value as the sender.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) SetBitSoup

func (e *Encryptor) SetBitSoup(mode int32)

SetBitSoup overrides the bit-soup mode for this encryptor. 0 = byte-level split (default); non-zero = bit-level "bit soup" split. Mutates only the encryptor's own itb.Config copy.

Auto-couple guard: when a dedicated lockSeed is active on this encryptor (cfg.LockSeed == 1, set either by Encryptor.SetLockSeed(1) or by NewMixed / NewMixed3 with a non-empty PrimitiveL), passing mode == 0 is silently overridden to mode == 1. The bit-permutation overlay must stay engaged while the dedicated lockSeed is allocated; allowing SetBitSoup(0) here would let a subsequent encrypt panic with ErrLockSeedOverlayOff inside the build-PRF closure when LockSoup is also off. Drop the dedicated lockSeed via Encryptor.SetLockSeed(0) first if a fully-overlay-off configuration is the goal.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) SetChunkSize

func (e *Encryptor) SetChunkSize(n int)

SetChunkSize overrides the streaming chunk size for this encryptor's subsequent Encryptor.EncryptStream calls. 0 selects the auto-detect heuristic from itb.ChunkSize. The value is ignored on the decrypt side — chunk extents are recovered from the wire-format header per chunk.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) SetLockSeed

func (e *Encryptor) SetLockSeed(mode int32)

SetLockSeed enables or disables the dedicated lockSeed for bit-permutation derivation on this encryptor. Valid values: 0 = off (default; bit-permutation derives from noiseSeed), 1 = on (a dedicated lockSeed of the same primitive / width is allocated lazily on the first SetLockSeed(1) call after construction; bit-permutation derives from the dedicated seed instead). Panics on any other value.

Auto-couples Lock Soup on the on-direction: when mode == 1 this also calls Encryptor.SetLockSoup(1) on the same encryptor, which through its own coupling engages BitSoup=1 — the dedicated lockSeed has no observable effect on the wire output unless the bit-permutation overlay is engaged, so coupling the two flags spares callers a second setter call. The off- direction does not auto-disable the overlay; callers that want to drop only the dedicated seed but keep the overlay engaged call SetLockSeed(0) without losing the Lock Soup / Bit Soup settings.

Calling SetLockSeed after the encryptor has produced its first ciphertext panics with ErrLockSeedAfterEncrypt — the bit- permutation derivation path cannot change mid-session without breaking decryptability of pre-switch ciphertext. Pre-Encrypt switching is allowed; mode toggles freely until the first encrypt.

Activating from the off state allocates a fresh CSPRNG-backed seed via the same factory used at New / New3 time and appends it to the encryptor's seeds + prfKeys slices. Deactivating zeroes the dedicated seed's components and PRF key, drops the LockSeedHandle from the itb.Config, and shrinks the slices back to 3 (Single) or 7 (Triple).

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) SetLockSoup

func (e *Encryptor) SetLockSoup(mode int32)

SetLockSoup overrides the Lock Soup overlay for this encryptor. 0 = off (default); non-zero = on. A non-zero value also coerces BitSoup to 1 on this encryptor, mirroring the existing global itb.SetLockSoup behaviour: the Lock Soup overlay layers on top of bit soup, so engaging the overlay engages bit soup as well.

Auto-couple guard mirrors Encryptor.SetBitSoup: when a dedicated lockSeed is active on this encryptor, passing mode == 0 is silently overridden to mode == 1 so the bit-permutation overlay stays engaged. Drop the dedicated lockSeed via Encryptor.SetLockSeed(0) first if a fully-overlay-off configuration is the goal.

Panics with ErrClosed when called after Encryptor.Close.

func (*Encryptor) SetNonceBits

func (e *Encryptor) SetNonceBits(n int)

SetNonceBits overrides the nonce size for this encryptor's subsequent encrypt / decrypt calls. Valid values: 128, 256, 512. Panics on invalid input — nonce misconfiguration is a security- critical bug.

Mutates only the encryptor's own itb.Config copy; the process-global itb.SetNonceBits is unaffected. Both sender and receiver must use the same value (the value is captured into the state blob via Encryptor.Export under future schemas; v1 leaves nonce_bits as a deployment-config concern).

Not safe for concurrent invocation with an in-flight encrypt / decrypt on the same encryptor — caller serialises if it needs concurrency on a single instance. Different encryptors run in parallel goroutines without cross-contamination.

Panics with ErrClosed when called after Encryptor.Close.

type ErrMismatch

type ErrMismatch struct {
	Field string
}

ErrMismatch indicates the state blob disagrees with the receiver's bound configuration on a specific field. Field is the canonical JSON field name that triggered the rejection.

func (*ErrMismatch) Error

func (e *ErrMismatch) Error() string

Error implements the error interface.

type MixedSpec

type MixedSpec struct {
	PrimitiveN string
	PrimitiveD string
	PrimitiveS string
	PrimitiveL string
	KeyBits    int
	MACName    string
}

MixedSpec describes the per-slot primitive selection for a Single-Ouroboros encryptor built via NewMixed. PrimitiveN / PrimitiveD / PrimitiveS are the canonical hashes.Registry names for the noise / data / start seed slots; PrimitiveL is the optional dedicated lockSeed primitive (empty string = no lockSeed allocation, behaves like New without Encryptor.SetLockSeed).

All four primitive names must resolve to the same native hash width — mixing widths in one Encryptor is forbidden by Go's seed type system and rejected with ErrEasyMixedWidth before any allocation runs.

KeyBits selects the per-seed key width in bits (one of 512, 1024, 2048; multiple of the resolved native width). MACName selects the MAC primitive across the encryptor (one MAC per encryptor, same as New / New3).

type MixedSpec3

type MixedSpec3 struct {
	PrimitiveN  string
	PrimitiveD1 string
	PrimitiveD2 string
	PrimitiveD3 string
	PrimitiveS1 string
	PrimitiveS2 string
	PrimitiveS3 string
	PrimitiveL  string
	KeyBits     int
	MACName     string
}

MixedSpec3 describes the per-slot primitive selection for a Triple-Ouroboros encryptor built via NewMixed3. PrimitiveN covers the shared noiseSeed slot; PrimitiveD1 / PrimitiveD2 / PrimitiveD3 cover the three dataSeed rings; PrimitiveS1 / PrimitiveS2 / PrimitiveS3 cover the three startSeed rings. PrimitiveL is the optional dedicated lockSeed primitive — empty string skips the lockSeed allocation (behaves like New3 without Encryptor.SetLockSeed).

All eight primitive names (seven slots plus the optional lockSeed) must resolve to the same native hash width; otherwise the constructor panics with ErrEasyMixedWidth before any allocation runs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL