Lumoin.Base.MemoryProtection 0.0.9

There is a newer version of this package available.
See the version list below for details.
dotnet add package Lumoin.Base.MemoryProtection --version 0.0.9
                    
NuGet\Install-Package Lumoin.Base.MemoryProtection -Version 0.0.9
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Lumoin.Base.MemoryProtection" Version="0.0.9" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Lumoin.Base.MemoryProtection" Version="0.0.9" />
                    
Directory.Packages.props
<PackageReference Include="Lumoin.Base.MemoryProtection" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Lumoin.Base.MemoryProtection --version 0.0.9
                    
#r "nuget: Lumoin.Base.MemoryProtection, 0.0.9"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Lumoin.Base.MemoryProtection@0.0.9
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Lumoin.Base.MemoryProtection&version=0.0.9
                    
Install as a Cake Addin
#tool nuget:?package=Lumoin.Base.MemoryProtection&version=0.0.9
                    
Install as a Cake Tool

<img style="display: block; margin-inline-start: auto; margin-inline-end: auto;" src="resources/lumoin-base-github-logo.svg" width="600" alt="Lumoin.Base project logo: a circular emblem of concentric dashed arcs in blue hues evoking layered bedrock, followed by the wordmark 'base'.">

Lumoin.Base

Dependency-free primitives shared across the Lumoin family of .NET libraries.

Main build workflow


Lumoin.Base holds the small set of primitives that every Lumoin library needs and none of them should own. It is dependency-free and AOT-, trim-, and browser-clean, so any family member — including browser/WASM builds — can consume it, and no member depends on another.

The repository ships three packages. Lumoin.Base is the dependency-free leaf: BaseMemoryPool, an exact-size, zero-on-return MemoryPool<byte> whose caller chooses how each buffer is backed (Managed, Pinned, or Native), and Tag, an immutable type-keyed metadata container. The native tier is an injection seam (NativeBackingAllocator), never a compiled-in dependency. Lumoin.Base.MemoryProtection implements that seam without libsodium: page-aligned allocations locked into physical memory through the operating system's own mechanism (VirtualLock on Windows, mlock plus best-effort MADV_DONTDUMP on Linux/Android, mlock on Apple platforms and FreeBSD), zeroed on free — pure P/Invoke into libraries every supported OS already ships (glibc and musl alike), so it carries no native assets at all. Lumoin.Base.Libsodium is the libsodium package: a raw crypto binding — Ed25519 seed-keypair generation, detached signing and verification, Ed25519-to-X25519 key conversion, X25519 scalar multiplication, XChaCha20-Poly1305 authenticated encryption, and the ML-KEM-768 (FIPS 203) and X-Wing hybrid post-quantum KEMs, with secret-key scratch composed by the caller as a MemoryPool<byte> — plus the libsodium implementation of the memory seam: SodiumBacking.Allocate serves AllocationKind.Native rents as per-rent isolated sodium_malloc guarded allocations (canary, guard pages, best-effort locking, zero on free; not available in the browser, and marked so). The libsodium 1.0.22 native library ships inside the package, built by this repository's CI from the pinned, checksum-verified upstream source, so the package works as-is from NuGet; on browser-wasm the same binding is statically linked at publish instead.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.14 125 9/13/2026
0.0.13 110 9/10/2026
0.0.12 121 9/2/2026
0.0.11 110 9/2/2026
0.0.10 114 9/1/2026
0.0.9 129 8/12/2026
0.0.8 145 7/27/2026
0.0.7 127 7/22/2026
0.0.6 150 7/11/2026

Added:
- Initial package: `Lumoin.Base`. Bedrock primitives shared across the Lumoin family.
- `BaseMemoryPool`: a `MemoryPool<byte>` that lets the caller choose how a buffer is backed
 through an `AllocationKind` passed at rent time (`Managed`, `Pinned`, `Native`), with exact-size
 slabs, deterministic zero-on-return, and OpenTelemetry metrics. Native backing is injected through
 the `NativeBackingAllocator` seam, keeping the assembly dependency-free and AOT / trim /
 browser-clean. A `Native` rent with no backing wired throws by default; the graceful fallback to
 `Pinned` is an explicit opt-in (`allowNativeDegradation`) and telemetry records the effective
 allocation kind plus a degradation event.
- `Tag`: a metadata container for purpose-specific classification of pooled memory.
- `SlabBufferWriter`: an `IBufferWriter<byte>` over a `MemoryPool<byte>` (e.g. `BaseMemoryPool`) that grows by
 renting linked slabs and `Detach()`-es into a single exact-length owned buffer — the streaming-serialization
 sink for the family, so writers never pre-size and never copy-to-grow.
- `SensitiveMemory` / `SensitiveData`: a domain-agnostic base for a pooled, `Tag`-carrying block of sensitive
 bytes that exposes only read-only views and clears its memory on disposal — so a naked `byte[]` never crosses a
 public boundary and potentially sensitive (e.g. reporting) bytes are wiped deterministically. Construction
 optionally accepts an OpenTelemetry `Activity` bounding the value's lifetime.
- `EmptyMemoryOwner`: a shared, allocation-free `IMemoryOwner<byte>` singleton over a zero-length buffer with a
 no-op dispose — the stand-in for empty payloads where a pool would reject a zero-size rental, and recognized by
 `SensitiveMemory` so shared `Empty` singletons are never wiped or poisoned.
- `SensitiveMemoryTelemetry`: the telemetry tag-key (`sensitive_memory.lifetime_ms`) the sensitive-memory
 primitives emit on the lifetime span.
- `Utf8String`: a non-owning, byte-native UTF-8 string value type (`readonly struct` over `ReadOnlyMemory<byte>`)
 for encoding and I/O boundaries — byte-defined equality/ordering with an optionally precomputed hash, zero-copy
 `Slice`/`Range` views, byte-search helpers, `IUtf8SpanFormattable`/`ISpanFormattable`, and an explicit
 `TryFromUtf8` validating factory (construction itself does not validate).
- `Utf8StringComparer`: equality, ordering, and zero-allocation alternate lookup by raw `ReadOnlySpan<byte>` for
 `Utf8String` (`IAlternateEqualityComparer`), so a `HashSet`/`Dictionary`/`FrozenSet` of `Utf8String` is probed
 with a `u8` literal or wire span without allocating. `Create(Utf8HashFunction)` swaps in a deterministic hash for
 bucketing that is stable across processes.
- `Utf8StringPool`: a single-writer arena that interns UTF-8 bytes into bulk-freed slabs rented from a
 `MemoryPool<byte>` (default a private `BaseMemoryPool`), with zero-allocation probing on a cache hit, a chosen
 `AllocationKind` for how interned memory is protected, UTF-8 validation on by default (opt out with
 `validateOnIntern: false`), OpenTelemetry metrics via `Utf8StringPoolMetrics`, and an optional static,
 application-installed `Instance` ambient pool (the library never creates one implicitly). Materialization is
 pool-only — there is no heap-allocating factory; `Utf8String` either views caller memory or is interned.
- `Utf8StringPool.Reset()`: bulk-reclaims all interned memory and clears the table so the pool can be reused
 without being recreated, with the same "no live views" contract as disposal — a cheap shrink for scoped reuse.
- `Utf8StringInterner`: a process-wide, thread-safe interner for recurring UTF-8 bytes and .NET strings — the
 concurrent, self-bounding counterpart to `Utf8StringPool`. Values live in hot/cold generations and the cold one
 is evicted when the hot fills, bounding the live set to about twice a configured capacity; eviction is safe
 because interned memory is managed and an outstanding `Utf8String` keeps its own bytes alive (the GC reclaims
 only once no view remains), so it never dangles a value already handed out. Cache hits are lock-free; `Clear()`
 drops everything; an optional static, application-installed `Instance` mirrors the pool's ambient. Managed-only
 by design (it relies on GC liveness, so no `Native`/`Pinned` backing). Optional OpenTelemetry metrics via
 `Utf8StringInternerMetrics` (intern, hit, and rotation counters plus a live-count gauge), and an optional maximum
 value length that returns oversized values uncached so no single value can bloat the resident set.
- Guarded-memory backing `SodiumBacking` (in `Lumoin.Base.Libsodium`): the libsodium
 implementation of the `NativeBackingAllocator` seam. Wiring `SodiumBacking.Allocate` into a
 `BaseMemoryPool` serves `AllocationKind.Native` rents as per-rent isolated `sodium_malloc`
 guarded allocations — canary, guard pages, best-effort memory locking, and zero on free — with
 `sodium_memzero` defense-in-depth and a finalizer backstop on the owner.
 `SodiumBacking.IsAvailable` reports whether the native library loaded so hosts wire the backing
 only where it exists. Not available on browser-wasm and marked `[UnsupportedOSPlatform]`
 accordingly. Briefly shipped as the separate package `Lumoin.Base.Sodium` (last release 0.0.7,
 now retired).
- Protected-slab native tier: `BaseMemoryPool` gains a pool-level `NativeRentMode`
 (`PerRentIsolated`, the default, or `ProtectedSlab`). In protected-slab mode injected backing
 regions are allocated on demand per buffer size, each subdivided into exact-size segments
 bracketed by per-segment software canaries (verified on return; a stomped canary zeroes the
 secret, retires the segment,
 records the `Lumoin.BaseMemoryPool.CanaryViolationsTotal` counter and a `CanaryViolation`
 activity event, and surfaces as the new `CanaryViolationException`). Density in place of
 per-secret hardware guards: hundreds of transient secrets fit a locked-memory budget that holds
 only a handful of isolated allocations. Native rent activities now carry a `nativeRentMode` tag,
 and `TrimExcess` reclaims idle protected regions.
- New package `Lumoin.Base.MemoryProtection`: the operating-system-twin implementation of the
 `NativeBackingAllocator` seam — no libsodium, no native assets, no dependencies beyond
 `Lumoin.Base`. `MemoryProtectionBacking.Allocate` serves `AllocationKind.Native` rents as
 page-aligned allocations locked into physical memory (`VirtualLock` on Windows, `mlock` plus
 best-effort `MADV_DONTDUMP` on Linux/Android, `mlock` on Apple platforms and FreeBSD; the C
 library resolves on glibc and musl alike), zeroed over the whole
 locked range on disposal, with the same idempotent-dispose and finalizer-backstop owner contract
 as the Sodium tier. Strict and loud: an exhausted locked-memory budget (`RLIMIT_MEMLOCK`, the
 Windows minimum working set) throws `InsufficientMemoryException` with the knob named — never a
 silent fallback to unlocked memory. The OS provides no guard pages or canary here; pair with
 `NativeRentMode.ProtectedSlab` for software-canary overrun detection on top of the locked
 region. `MemoryProtectionBacking.IsSupported` reports platform support.
- New package `Lumoin.Base.Libsodium`, the family's one libsodium package: a raw crypto binding -
 Ed25519 seed-keypair generation, detached signing and verification, Ed25519-to-X25519 key
 conversion, X25519 scalar multiplication, XChaCha20-Poly1305 authenticated encryption, and the
 ML-KEM-768 (FIPS 203) and X-Wing hybrid post-quantum KEMs, with secret-key scratch memory
 composed by the caller as a `MemoryPool<byte>` (guarded native, locked, pinned, or managed
 backing) - plus the `SodiumBacking` guarded-memory seam implementation described above. Depends
 only on `Lumoin.Base`. The libsodium 1.0.22 native library ships inside the package
 (win-x64, win-arm64, linux-x64, linux-arm64, osx-x64, osx-arm64, android-arm64, android-x64;
 iOS and Mac Catalyst link a bundled static xcframework through the package's buildTransitive
 targets), built by the family from the pinned, checksum-verified upstream release source, so
 the package works as-is from NuGet; on browser-wasm the same binding is statically linked at
 publish instead. Binaries the build runner can load are proven by running the package's own
 test suite against them; cross-compiled mobile binaries ship on pinned-source provenance with
 architecture and exported-symbol verification. The package multi-targets `net10.0` plus
 `net10.0-ios`/`net10.0-maccatalyst`; the Apple assemblies import via `__Internal`, resolving
 against the statically linked xcframework the buildTransitive targets wire into the app build.

Changed:
- Toolchain refresh: .NET SDK 10.0.400 (the wasm smoke pins .NET 11 preview 7), MSTest 4.3.3,
 Microsoft.Testing.Extensions 2.3.3, CsCheck 4.8.0, System.Security.Cryptography.Xml 10.0.11,
 and harden-runner v2.20.1.
- Package `Lumoin.Base.Sodium` is retired: its guarded-memory backing (`SodiumBacking`,
 namespace now `Lumoin.Base.Libsodium`) ships in `Lumoin.Base.Libsodium`. 0.0.7 remains the
 last release of the retired id.
- `SensitiveMemory`: documented the wipe's threat model — exposure it reduces versus what it cannot defend, and
 that the wipe is only fully reliable on non-relocatable (`Pinned`/`Native`) backing.
- `SensitiveMemory`: `Dispose` now stops and stamps an optional OpenTelemetry lifetime `Activity`, and skips
 wiping/disposing (and the disposed-state transition) when backed by the shared `EmptyMemoryOwner`.
- `SlabBufferWriter`: its empty-detach owner is now the shared `EmptyMemoryOwner` rather than a private copy.
- `Tag`: redesigned as a bespoke type with content-based, order-independent equality (the previous record
 derived equality from its backing dictionary, comparing by reference). The `(Type, object)` tuple factory
 overloads, the `Data` property, and the `Type` indexer are removed in favor of the typed `Create<T>` /
 `With<T>` / `Get<T>` / `TryGet<T>` / `Contains<T>` API and a read-only `Entries` projection. **Breaking.**
- Segment clearing throughout the pool now uses `CryptographicOperations.ZeroMemory` instead of
 `Span.Clear`/`Array.Clear`, so the zeroing of returned secrets cannot be elided.
- `BaseMemoryPool` constructors gained the optional `nativeRentMode` parameter (source-compatible;
 recompile against this version).
- Dependency refresh across the repository: .NET SDK 10.0.302; MSTest 4.3.2;
 Microsoft.Testing.Platform extensions 2.3.2; LiquidTestReports.Markdown 2.0.0-beta.6; and the
 build-time `System.Security.Cryptography.Xml` pin at 10.0.10, addressing published advisories
 against 10.0.9. The pinned `actions/checkout` and `actions/setup-dotnet` CI actions moved to
 their latest releases.

See full changelog at https://github.com/Lumoin/Lumoin.Base/blob/main/CHANGELOG.md.