Frame Pipeline
On this page
Namespace: Nalix.Codec.Transforms
Assembly: Nalix.Codec
FramePipeline unifies the execution of cryptographic (EnvelopeCipher) and compression (LZ4Codec) transforms for inbound and outbound frames, preserving the 6-byte PacketHeader (FrameTransformer.Offset = 6) while transforming the payload region (DATA_REGION).
Source Mapping
src/Nalix.Codec/Transforms/FramePipeline.cssrc/Nalix.Codec/Transforms/FrameCipher.cssrc/Nalix.Codec/Transforms/FrameCompression.cssrc/Nalix.Codec/Transforms/FrameTransformer.cs
Canonical Wire Order
- Outbound (
ProcessOutbound): Compress first (PacketFlags.COMPRESSED) $\rightarrow$ Encrypt (PacketFlags.ENCRYPTED). - Inbound (
TryProcessInbound/ProcessInbound): Decrypt first $\rightarrow$ Decompress.
Public API
| Method | Signature | Description |
|---|---|---|
TryProcessInbound | public static bool TryProcessInbound([Borrowed] ref IBufferLease current, ReadOnlySpan<byte> secret, CipherSuiteType algorithm, out uint? seq) | Non-throwing inbound pipeline. Decrypts and/or decompresses current in place (swapping current to a newly rented BufferLease if transformed). Returns false if decryption, authentication, or decompression fails. |
ProcessInbound | public static void ProcessInbound([Borrowed] ref IBufferLease current, ReadOnlySpan<byte> secret, CipherSuiteType algorithm, out uint? seq) | Throwing inbound pipeline. Throws ArgumentNullException (if current is null) or CipherException (on decryption, authentication, or decompression failure). |
ProcessOutbound | public static void ProcessOutbound([Borrowed] ref IBufferLease current, bool enableCompress, int minSizeToCompress, bool enableEncrypt, ReadOnlySpan<byte> secret, uint? seq, CipherSuiteType algorithm) | Applies outbound LZ4 compression (when payloadSize >= minSizeToCompress and compression saves $\ge 12.5%$) and envelope encryption. Throws ArgumentNullException, CipherException (including when seq.HasValue is false and encryption is enabled, validated up-front before compression when doCompress && enableEncrypt), LZ4Exception, or InternalErrorException. |
Key Runtime & Security Invariants
- 12.5% Minimum Compression Gain (
IsCompressionWorthwhile):- Outbound compression is only kept when
compressedLength <= originalLength - (originalLength >> 3)(at least 12.5% smaller). If a payload is incompressible,FramePipelinesends the raw payload withoutPacketFlags.COMPRESSED.
- Outbound compression is only kept when
- Fused Single-Allocation Paths:
- Outbound (
ProcessOutboundFused): When both compression and encryption are active, validatesseq.HasValueup-front, rents a singleBufferLease(BufferLease.TransportHeadroomreserved) with a scratch tail region, compresses into the tail, encrypts into the main region, wipes the scratch tail, and commits the final length. - Inbound (
TryProcessInboundFused): When a frame has bothPacketFlags.ENCRYPTEDandPacketFlags.COMPRESSED, decrypts into a temporary pooled array (cleared infinally), validates the LZ4 header viaFrameTransformer.TryGetDecompressedLengthagainstMath.Min(CompressionOptions.MaxDecompressedSize, LZ4CompressionConstants.MaxBlockSize)(256 KBcap), and decompresses directly into the finalBufferLease.
- Outbound (
- Plaintext Scrubbing &
EncryptedOnWireTracking:- When
ProcessOutboundencrypts a plaintextBufferLease, it setsplaintextLease.ZeroOnDispose = trueso the source plaintext is scrubbed when returned to the pool. - When
TryProcessInbound/FrameCipherdecrypts an inbound frame, the resulting plaintext lease hasEncryptedOnWire = trueandZeroOnDispose = true, while the transientPacketFlags.ENCRYPTEDandPacketFlags.COMPRESSEDbits are cleared fromheader.Flags. Downstream handlers and[PacketEncryption(true)]inspectlease.EncryptedOnWire(context.IsEncrypted).
- When
- Borrowed Reference Swap Ownership:
FramePipelinemutatesref IBufferLease currentby swapping the reference to the new transformed lease and disposing any intermediate lease it created, but never disposes the caller’s originalcurrentlease (allowing the caller to manage original lease lifetime deterministically).
Usage Example
using Nalix.Abstractions.Networking.Packets;
using Nalix.Abstractions.Security;
using Nalix.Codec.Transforms;
// Outbound: compress payloads >= 512 bytes and encrypt with ChaCha20-Poly1305
IBufferLease originalOut = OutboundLease;
IBufferLease currentOut = originalOut;
FramePipeline.ProcessOutbound(
ref currentOut,
enableCompress: true,
minSizeToCompress: 512,
enableEncrypt: true,
secret: sessionSecret,
seq: nextOutboundSeq,
algorithm: CipherSuiteType.Chacha20Poly1305);
// Inbound: non-throwing decrypt + decompress on network receive loop
IBufferLease originalIn = InboundLease;
IBufferLease currentIn = originalIn;
if (FramePipeline.TryProcessInbound(
ref currentIn,
secret: sessionSecret,
algorithm: CipherSuiteType.Chacha20Poly1305,
out uint? envelopeSeq))
{
// currentIn now holds decrypted/decompressed packet bytes (EncryptedOnWire == true)
}