HideProtocol 0.7.0

dotnet add package HideProtocol --version 0.7.0
                    
NuGet\Install-Package HideProtocol -Version 0.7.0
                    
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="HideProtocol" Version="0.7.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="HideProtocol" Version="0.7.0" />
                    
Directory.Packages.props
<PackageReference Include="HideProtocol" />
                    
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 HideProtocol --version 0.7.0
                    
#r "nuget: HideProtocol, 0.7.0"
                    
#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 HideProtocol@0.7.0
                    
#: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=HideProtocol&version=0.7.0
                    
Install as a Cake Addin
#tool nuget:?package=HideProtocol&version=0.7.0
                    
Install as a Cake Tool

HideProtocol for .NET

Experimental and unaudited. HIDE is hybrid post-quantum (X25519 + ML-KEM-768, Ed25519 + ML-DSA-65). See the security policy.

.NET 8+ binding, through P/Invoke, to the same Rust core (crates/hide-ffi) that the CLI and every other HIDE SDK use. This package contains no cryptography of its own.

Install

dotnet add package HideProtocol

One nupkg carries the compiled core for all seven runtime identifiers under runtimes/<rid>/native/: linux-x64, linux-arm64, linux-musl-x64, win-x64, win-arm64, osx-x64, osx-arm64. The runtime picks the right one; no toolchain is needed. On any other platform, build the core yourself and point the binding at it (see Native library).

Quick start

using HideProtocol;

using (SecretKey secret = SecretKey.Generate())
{
    byte[] box = Hide.Encrypt("hello"u8, [secret.PublicKey()], filename: "note.txt");
    Decrypted opened = Hide.Decrypt(box, secret);
    Console.WriteLine($"{System.Text.Encoding.UTF8.GetString(opened.Plaintext)} {opened.FileName}");
    // hello note.txt

    byte[] tampered = (byte[])box.Clone();
    tampered[^1] ^= 1;
    try
    {
        Hide.Decrypt(tampered, secret);
    }
    catch (AuthenticationException e)
    {
        Console.WriteLine($"refused: {e.Message}");
        // refused: authentication failed; the data was altered
    }
}

Hide.Encrypt(plaintext, recipients, filename?, mediaType?) takes 1..64 recipient public keys, each exactly Hide.PublicKeyLength (1216) bytes. Hide.Decrypt returns a Decrypted record with Plaintext, FileName and MediaType; nothing is returned unless the whole payload authenticates. FileName is attacker-controlled: never use it to choose an output path. Metadata passed into Encrypt may not contain a NUL byte; it is rejected rather than silently truncated.

Keys on disk: secret.Protect(passphrase) returns a sealed key file (Hide.MinPassphraseLength is 8, and there is no escrow); SecretKey.Open(bytes, passphrase) opens one; Hide.InspectKey(bytes) reports KeyKind.Raw or KeyKind.Protected without the passphrase. Hide.ArmorPublicKey / Hide.DearmorPublicKey give a public key a pasteable text form.

Errors: every failure is a HideExceptionAuthenticationException (altered, or not a container), its subclass MalformedException (did not decode at all), WrongPassphraseException, NoMatchingRecipientException, NotAKeyException, ChallengeExpiredException, ChallengeReplayedException. Arguments this binding rejects before calling the core throw ArgumentException.

Signing and verification

One seed backs both encryption and signing, so there is a single thing to back up.

byte[] sealedKey = SigningIdentity.Generate("correct horse battery");   // store this

using (SigningIdentity signer = SigningIdentity.Load(sealedKey, "correct horse battery"))
using (SpentNonces spent = new())                                        // must outlive one request
{
    byte[] context = "myapp/v1 release"u8.ToArray();
    byte[] message = "payload"u8.ToArray();
    byte[] signature = signer.Sign(context, message);                    // 3373 bytes
    Hide.Verify(signer.PublicKey(), context, message, signature);        // void; throws on failure

    // Challenge/response: good once, here, now.
    ulong now = (ulong)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
    byte[] challenge = Hide.NewChallenge("app.example", now, 60);
    byte[] answer = signer.Answer(challenge);
    spent.Accept(challenge, answer, signer.PublicKey(), now);
    spent.Accept(challenge, answer, signer.PublicKey(), now);            // ChallengeReplayedException
}

context separates uses of one identity so a signature made for one purpose cannot be replayed as another; never let a remote party choose it. Hide.Verify returns void and throws AuthenticationException on failure rather than returning a boolean a caller could forget to check. A key file written before signatures existed carries no signing seed and throws NotAKeyException.

Identity logs, epoch chains, transparency proofs

Method Returns
Hide.VerifyIdentity(log, recoveryKey) int — how many devices the log trusts now
Hide.IdentityTrustsDevice(log, recoveryKey, devicePublicKey) bool — membership, after verifying the log
Hide.IdentityHead(log, recoveryKey) 32 bytes naming this exact history
Hide.VerifyEpochChain(chain) int — how many epochs it holds
Hide.EpochPublicKey(chain, ulong epoch) the public key to encrypt to for epoch
Hide.VerifyInclusion(leaf, ulong index, ulong size, path, root) void
Hide.VerifyConsistency(ulong oldSize, ulong newSize, path, oldRoot, newRoot) void

A cryptographic verify throws on failure (MalformedException if the bytes did not decode, AuthenticationException if they decoded but did not verify) and never returns false. The one boolean is IdentityTrustsDevice: the log is verified first, so false means "not a member", never "did not verify".

Native library

The core is located in this order:

  1. HIDE_LIBRARY, if it names a file and HIDE_ALLOW_LIBRARY_OVERRIDE=1 is also set;
  2. hide_ffi.dll / libhide_ffi.dylib / libhide_ffi.so beside the assembly — the package's runtimes/<rid>/native/ copy lands here;
  3. the platform's default probing paths.

HIDE_LIBRARY is a development override: it replaces the entire cryptographic core, so a single settable environment variable must not be enough to redirect it. Against a local build:

cargo build --release -p hide-ffi
$env:HIDE_LIBRARY = "$PWD\target\release\hide_ffi.dll"
$env:HIDE_ALLOW_LIBRARY_OVERRIDE = '1'
cargo build --release -p hide-ffi
export HIDE_LIBRARY="$PWD/target/release/libhide_ffi.so"   # libhide_ffi.dylib on macOS
export HIDE_ALLOW_LIBRARY_OVERRIDE=1

Key material

SecretKey, SigningIdentity and SpentNonces are opaque IDisposable handles. The seed bytes never cross into managed memory and this SDK exposes no accessor for them; ToString() renders nothing derived from the key. Release with Dispose() or a using statement; a finalizer backstops it, but relying on it keeps key material in memory for an unbounded time. A disposed handle throws ObjectDisposedException on use.

Limits

  • Unaudited. Do not protect data you cannot afford to lose or expose.
  • An identity is a key, not a person: a verified signature proves possession of a seed, nothing about who holds it.
  • Full threat model: docs/threat-model.md.
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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.
  • net8.0

    • No dependencies.

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.7.0 103 9/8/2026
0.6.2 94 9/8/2026
0.6.1 88 9/8/2026
0.6.0 89 9/7/2026
0.5.0 90 9/7/2026