C# API Reference

Complete API documentation for MetaMUI Crypto Primitives in C#.

Installation

Using NuGet Package Manager

# Package Manager Console
Install-Package MetaMUI.Crypto -Version 3.0.0

# .NET CLI
dotnet add package MetaMUI.Crypto --version 3.0.0

# PackageReference
<PackageReference Include="MetaMUI.Crypto" Version="3.0.0" />

Platform Support

Quick Start

using MetaMUI.Crypto;
using MetaMUI.Crypto.Signatures;
using MetaMUI.Crypto.Encryption;
using System;
using System.Text;

class Program
{
    static void Main()
    {
        // Generate Ed25519 keypair
        var keypair = Ed25519.GenerateKeypair();
        
        // Sign a message
        byte[] message = Encoding.UTF8.GetBytes("Hello, World!");
        byte[] signature = Ed25519.Sign(message, keypair.PrivateKey);
        
        // Verify signature
        bool isValid = Ed25519.Verify(signature, message, keypair.PublicKey);
        
        Console.WriteLine($"Signature valid: {isValid}");
    }
}

API Documentation

For detailed API documentation, see:

Namespace Organization

using MetaMUI.Crypto;              // Core functionality
using MetaMUI.Crypto.Hash;         // Hash functions
using MetaMUI.Crypto.Signatures;   // Digital signatures
using MetaMUI.Crypto.Encryption;   // Symmetric encryption
using MetaMUI.Crypto.KeyExchange;  // Key exchange
using MetaMUI.Crypto.KeyDerivation;// Key derivation
using MetaMUI.Crypto.PostQuantum;  // Post-quantum algorithms
using MetaMUI.Crypto.Utilities;    // Utility functions

Async/Await Support

Async Hash Operations

using MetaMUI.Crypto.Hash;

// Async hashing
byte[] hash = await Sha256.ComputeHashAsync(data);

// Async streaming hash
await using var stream = File.OpenRead("large_file.bin");
byte[] fileHash = await Blake3.ComputeHashAsync(stream);

// Async with progress
var progress = new Progress<long>(bytes =>
    Console.WriteLine($"Processed {bytes} bytes"));
    
byte[] hashWithProgress = await Blake3.ComputeHashAsync(
    stream, progress, cancellationToken);

Async Encryption

using MetaMUI.Crypto.Encryption;

// Async encryption
var cipher = new ChaCha20Poly1305(key);
var (ciphertext, tag) = await cipher.EncryptAsync(
    plaintext, nonce, associatedData);

// Async decryption
byte[] decrypted = await cipher.DecryptAsync(
    ciphertext, nonce, tag, associatedData);

Async Key Derivation

using MetaMUI.Crypto.KeyDerivation;

// Async Argon2 (CPU-intensive)
byte[] hash = await Argon2.HashPasswordAsync(
    password, salt,
    iterations: 3,
    memorySize: 65536,
    parallelism: 4);

// With cancellation
byte[] key = await Pbkdf2.DeriveKeyAsync(
    password, salt, 100000, 32, cancellationToken);

Memory Management

IDisposable Pattern

// Automatic cleanup with using statement
using (var keypair = Ed25519.GenerateKeypair())
{
    // Use keypair
    byte[] signature = Ed25519.Sign(message, keypair.PrivateKey);
} // Private key automatically cleared from memory

// Async disposal (.NET Core 3.0+)
await using (var cipher = new ChaCha20Poly1305(key))
{
    var encrypted = await cipher.EncryptAsync(data, nonce);
}

SecureString Support

using System.Security;
using MetaMUI.Crypto.Utilities;

// Create SecureString
SecureString securePassword = new SecureString();
foreach (char c in "myPassword")
    securePassword.AppendChar(c);
securePassword.MakeReadOnly();

// Use with crypto operations
byte[] hash = Argon2.HashPassword(securePassword, salt);

// Clear sensitive data
using (var secureBytes = new SecureBytes(32))
{
    RandomNumberGenerator.Fill(secureBytes.Buffer);
    // Use secure bytes
} // Automatically cleared

Span and Memory Support

// Stack-allocated buffers
Span<byte> hash = stackalloc byte[32];
Sha256.ComputeHash(data, hash);

// Memory-efficient operations
ReadOnlySpan<byte> input = GetLargeData();
Span<byte> output = new byte[input.Length + 16];
ChaCha20Poly1305.Encrypt(input, output, key, nonce);

Error Handling

Exception Types

using MetaMUI.Crypto.Exceptions;

try
{
    var result = SomeOperation();
}
catch (InvalidKeyException ex)
{
    Console.WriteLine($"Invalid key: {ex.Message}");
}
catch (DecryptionException ex)
{
    Console.WriteLine($"Decryption failed: {ex.Message}");
}
catch (SignatureVerificationException ex)
{
    Console.WriteLine($"Signature invalid: {ex.Message}");
}
catch (CryptographicException ex)
{
    Console.WriteLine($"Crypto error: {ex.Message}");
}

Result Pattern

// Using Result<T> for error handling without exceptions
Result<byte[]> result = ChaCha20Poly1305.TryDecrypt(
    ciphertext, nonce, tag, key);

if (result.IsSuccess)
{
    byte[] plaintext = result.Value;
}
else
{
    Console.WriteLine($"Decryption failed: {result.Error}");
}

Hash Functions

SHA-256/512

using MetaMUI.Crypto.Hash;

// Simple hashing
byte[] hash256 = Sha256.ComputeHash(data);
byte[] hash512 = Sha512.ComputeHash(data);

// Streaming hash
using var sha256 = Sha256.CreateHasher();
sha256.Update(chunk1);
sha256.Update(chunk2);
byte[] hash = sha256.Finalize();

// Hash string directly
string hashHex = Sha256.ComputeHashString("Hello");

BLAKE2b/2s

// Standard BLAKE2b (512-bit output)
byte[] hash = Blake2b.ComputeHash(data);

// Custom output size
byte[] hash256 = Blake2b.ComputeHash(data, outputSize: 32);

// Keyed hashing (MAC)
byte[] mac = Blake2b.ComputeHash(data, key: secretKey);

// BLAKE2s (256-bit)
byte[] hash2s = Blake2s.ComputeHash(data);

BLAKE3

// Standard hash
byte[] hash = Blake3.ComputeHash(data);

// Keyed hash
byte[] keyedHash = Blake3.ComputeKeyedHash(data, key);

// Derive key
byte[] derivedKey = Blake3.DeriveKey(
    context: "my-app 2024-01-01",
    material: inputKeyMaterial,
    outputSize: 32);

// Streaming with multiple inputs
using var hasher = Blake3.CreateHasher();
hasher.Update(header);
hasher.Update(body);
hasher.Update(footer);
byte[] hash = hasher.Finalize();

Digital Signatures

Ed25519

using MetaMUI.Crypto.Signatures;

// Generate keypair
var keypair = Ed25519.GenerateKeypair();

// Export keys
byte[] publicKeyBytes = keypair.PublicKey.ToBytes();
byte[] privateKeyBytes = keypair.PrivateKey.ToBytes();

// Import keys
var publicKey = Ed25519PublicKey.FromBytes(publicKeyBytes);
var privateKey = Ed25519PrivateKey.FromBytes(privateKeyBytes);

// Sign
byte[] signature = Ed25519.Sign(message, privateKey);

// Verify
bool valid = Ed25519.Verify(signature, message, publicKey);

// Batch verification
var signatures = new[] { sig1, sig2, sig3 };
var messages = new[] { msg1, msg2, msg3 };
var publicKeys = new[] { pk1, pk2, pk3 };

bool[] results = Ed25519.BatchVerify(signatures, messages, publicKeys);

Sr25519

// Generate keypair with seed
byte[] seed = RandomNumberGenerator.GetBytes(32);
var keypair = Sr25519.GenerateKeypair(seed);

// Sign with context
byte[] signature = Sr25519.SignWithContext(
    message, keypair.PrivateKey, 
    context: Encoding.UTF8.GetBytes("substrate"));

// Verify with context
bool valid = Sr25519.VerifyWithContext(
    signature, message, keypair.PublicKey,
    context: Encoding.UTF8.GetBytes("substrate"));

// VRF (Verifiable Random Function)
var (output, proof) = Sr25519.VrfSign(
    message, keypair.PrivateKey);

bool vrfValid = Sr25519.VrfVerify(
    message, keypair.PublicKey, output, proof);

Encryption

ChaCha20-Poly1305

using MetaMUI.Crypto.Encryption;

// Create cipher
var cipher = new ChaCha20Poly1305(key);

// Encrypt with associated data
byte[] nonce = RandomNumberGenerator.GetBytes(12);
byte[] associatedData = Encoding.UTF8.GetBytes("metadata");

var (ciphertext, tag) = cipher.Encrypt(
    plaintext, nonce, associatedData);

// Decrypt and verify
byte[] decrypted = cipher.Decrypt(
    ciphertext, nonce, tag, associatedData);

// In-place encryption (modifies buffer)
byte[] buffer = (byte[])plaintext.Clone();
cipher.EncryptInPlace(buffer, nonce, out byte[] authTag);

AES-256-GCM

// Using .NET's built-in AES with our wrapper
using var aes = Aes256Gcm.Create(key);

// Generate IV
byte[] iv = RandomNumberGenerator.GetBytes(12);

// Encrypt
var (ciphertext, tag) = aes.Encrypt(plaintext, iv, associatedData);

// Decrypt
byte[] plaintext = aes.Decrypt(ciphertext, iv, tag, associatedData);

// Using hardware acceleration when available
if (Aes256Gcm.IsHardwareAccelerated)
{
    Console.WriteLine("Using AES-NI hardware acceleration");
}

Key Exchange

X25519

using MetaMUI.Crypto.KeyExchange;

// Generate keypairs
var alice = X25519.GenerateKeypair();
var bob = X25519.GenerateKeypair();

// Compute shared secrets
byte[] aliceShared = X25519.ComputeSharedSecret(
    alice.PrivateKey, bob.PublicKey);
    
byte[] bobShared = X25519.ComputeSharedSecret(
    bob.PrivateKey, alice.PublicKey);

// aliceShared == bobShared
Debug.Assert(aliceShared.SequenceEqual(bobShared));

Post-Quantum Algorithms

ML-KEM-768

using MetaMUI.Crypto.PostQuantum;

// Generate keypair
var keypair = MlKem768.GenerateKeypair();

// Encapsulation (sender)
var (ciphertext, sharedSecret) = MlKem768.Encapsulate(
    keypair.PublicKey);

// Decapsulation (receiver)
byte[] sharedSecret2 = MlKem768.Decapsulate(
    ciphertext, keypair.PrivateKey);

// Both parties have same shared secret
Debug.Assert(sharedSecret.SequenceEqual(sharedSecret2));

// Hybrid mode (X25519 + ML-KEM)
var hybrid = new HybridKem(X25519.Instance, MlKem768.Instance);
var (hybridCt, hybridSs) = hybrid.Encapsulate(hybridPublicKey);

Dilithium

// Generate keypair
var keypair = Dilithium3.GenerateKeypair();

// Sign message
byte[] signature = Dilithium3.Sign(message, keypair.PrivateKey);

// Verify signature
bool valid = Dilithium3.Verify(
    signature, message, keypair.PublicKey);

// Deterministic signatures
byte[] detSig = Dilithium3.SignDeterministic(
    message, keypair.PrivateKey);

// Serialization
byte[] publicKeyBytes = keypair.PublicKey.Serialize();
byte[] privateKeyBytes = keypair.PrivateKey.Serialize();

// Deserialization
var publicKey = DilithiumPublicKey.Deserialize(publicKeyBytes);
var privateKey = DilithiumPrivateKey.Deserialize(privateKeyBytes);

Key Derivation

Argon2

using MetaMUI.Crypto.KeyDerivation;

// Hash password
var salt = RandomNumberGenerator.GetBytes(16);
var hash = Argon2.HashPassword(
    password: "user_password",
    salt: salt,
    timeCost: 3,        // iterations
    memoryCost: 65536,  // 64 MB
    parallelism: 4,     // threads
    outputLength: 32);

// Verify password
bool valid = Argon2.VerifyPassword(
    password: "user_password",
    hash: storedHash);

// Derive encryption key
byte[] key = Argon2.DeriveKey(
    password: securePassword,
    salt: salt,
    outputLength: 32,
    options: new Argon2Options
    {
        Type = Argon2Type.Argon2id,
        Version = Argon2Version.V13,
        TimeCost = 4,
        MemoryCost = 131072,
        Parallelism = 8
    });

PBKDF2

// Derive key from password
byte[] salt = RandomNumberGenerator.GetBytes(32);
byte[] key = Pbkdf2.DeriveKey(
    password: password,
    salt: salt,
    iterations: 100000,
    outputLength: 32,
    prf: HashAlgorithmName.SHA256);

// With progress callback
byte[] key = Pbkdf2.DeriveKey(
    password, salt, 100000, 32,
    progress: (current, total) =>
        Console.WriteLine($"Progress: {current}/{total}"));

HKDF

// Extract and expand
byte[] prk = Hkdf.Extract(
    HashAlgorithmName.SHA256,
    inputKeyMaterial,
    salt);

byte[] okm = Hkdf.Expand(
    HashAlgorithmName.SHA256,
    prk,
    outputLength: 42,
    info: Encoding.UTF8.GetBytes("my-app"));

// One-shot operation
byte[] derivedKey = Hkdf.DeriveKey(
    HashAlgorithmName.SHA256,
    inputKeyMaterial,
    outputLength: 32,
    salt: salt,
    info: contextInfo);

Utility Functions

Secure Random

using MetaMUI.Crypto.Utilities;

// Generate random bytes
byte[] randomBytes = SecureRandom.GetBytes(32);

// Generate random integer
int randomInt = SecureRandom.GetInt32();
int randomInRange = SecureRandom.GetInt32(100); // 0-99

// Generate random double
double randomDouble = SecureRandom.GetDouble(); // 0.0-1.0

// Fill existing buffer
byte[] buffer = new byte[64];
SecureRandom.Fill(buffer);

// Thread-safe instance
var rng = SecureRandom.Create();
byte[] data = rng.GetBytes(16);

Constant-Time Operations

using MetaMUI.Crypto.Utilities;

// Constant-time comparison
bool equal = ConstantTime.Equals(computed, expected);

// Constant-time selection
byte[] selected = ConstantTime.Select(condition, ifTrue, ifFalse);

// Constant-time byte operations
byte result = ConstantTime.ConditionalSelect(
    condition, valueIfTrue, valueIfFalse);

// Clear sensitive data
ConstantTime.Clear(sensitiveBuffer);

Encoding/Decoding

using MetaMUI.Crypto.Utilities;

// Hex encoding
string hex = Hex.Encode(data);
byte[] decoded = Hex.Decode(hexString);

// Base64
string base64 = Base64.Encode(data);
byte[] decoded = Base64.Decode(base64String);

// Base64 URL-safe
string base64Url = Base64Url.Encode(data);
byte[] decoded = Base64Url.Decode(base64UrlString);

// Base32
string base32 = Base32.Encode(data);
byte[] decoded = Base32.Decode(base32String);

Platform-Specific Features

.NET Core Hardware Intrinsics

using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;

if (Avx2.IsSupported)
{
    // Use AVX2-optimized implementations
    Blake3.UseAvx2 = true;
}

if (AesNi.IsSupported)
{
    // Use AES-NI hardware acceleration
    Aes256Gcm.UseHardwareAcceleration = true;
}

// Check available intrinsics
var capabilities = CryptoCapabilities.GetHardwareCapabilities();
Console.WriteLine($"AES-NI: {capabilities.AesNi}");
Console.WriteLine($"SHA: {capabilities.Sha}");
Console.WriteLine($"AVX2: {capabilities.Avx2}");

Unity Integration

using UnityEngine;
using MetaMUI.Crypto;

public class CryptoManager : MonoBehaviour
{
    private Ed25519Keypair keypair;
    
    void Start()
    {
        // Generate keypair on startup
        keypair = Ed25519.GenerateKeypair();
        
        // Save to PlayerPrefs
        PlayerPrefs.SetString("PublicKey", 
            Base64.Encode(keypair.PublicKey.ToBytes()));
    }
    
    public byte[] SignData(byte[] data)
    {
        return Ed25519.Sign(data, keypair.PrivateKey);
    }
}

Blazor WebAssembly

@using MetaMUI.Crypto
@inject IJSRuntime JS

<button @onclick="GenerateKey">Generate Key</button>

@code {
    private async Task GenerateKey()
    {
        // Run crypto operations
        var keypair = await Task.Run(() => 
            Ed25519.GenerateKeypair());
        
        // Store in browser storage
        await JS.InvokeVoidAsync("localStorage.setItem", 
            "publicKey", Base64.Encode(keypair.PublicKey.ToBytes()));
    }
}

Performance Optimization

Parallel Operations

using System.Threading.Tasks.Dataflow;

// Parallel hashing
var hashes = await Task.WhenAll(
    files.Select(async file =>
        await Blake3.ComputeHashAsync(file)));

// Using DataFlow for pipeline
var hashBlock = new TransformBlock<byte[], byte[]>(
    async data => await Blake3.ComputeHashAsync(data),
    new ExecutionDataflowBlockOptions
    {
        MaxDegreeOfParallelism = Environment.ProcessorCount
    });

Buffer Pooling

using System.Buffers;

// Rent buffer from pool
byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);
try
{
    // Use buffer for crypto operations
    int bytesWritten = cipher.Encrypt(input, buffer);
    
    // Process encrypted data
    ProcessData(buffer.AsSpan(0, bytesWritten));
}
finally
{
    // Return buffer to pool
    ArrayPool<byte>.Shared.Return(buffer, clearArray: true);
}

SIMD Operations

using System.Numerics;

// Vector operations for batch processing
public static void XorBlocks(Span<byte> output, 
    ReadOnlySpan<byte> input1, ReadOnlySpan<byte> input2)
{
    int vectorSize = Vector<byte>.Count;
    int i = 0;
    
    for (; i <= output.Length - vectorSize; i += vectorSize)
    {
        var v1 = new Vector<byte>(input1.Slice(i, vectorSize));
        var v2 = new Vector<byte>(input2.Slice(i, vectorSize));
        (v1 ^ v2).CopyTo(output.Slice(i, vectorSize));
    }
    
    // Handle remaining bytes
    for (; i < output.Length; i++)
    {
        output[i] = (byte)(input1[i] ^ input2[i]);
    }
}

Security Best Practices

Key Management

using MetaMUI.Crypto.KeyManagement;

// Secure key storage
var keyStore = new SecureKeyStore("MyApp");

// Store key
await keyStore.StoreKeyAsync("user-key", keyMaterial,
    new KeyProtectionOptions
    {
        RequireAuthentication = true,
        ValidityPeriod = TimeSpan.FromDays(30)
    });

// Retrieve key
using var key = await keyStore.GetKeyAsync("user-key");

// Rotate keys
await keyStore.RotateKeyAsync("user-key", newKeyMaterial);

// Delete key
await keyStore.DeleteKeyAsync("user-key");

Secure Coding Patterns

// Use SecureString for passwords
public static byte[] HashPassword(SecureString password, byte[] salt)
{
    IntPtr ptr = IntPtr.Zero;
    try
    {
        ptr = Marshal.SecureStringToGlobalAllocUnicode(password);
        // Use password
        return Argon2.HashPassword(ptr, password.Length * 2, salt);
    }
    finally
    {
        if (ptr != IntPtr.Zero)
        {
            Marshal.ZeroFreeGlobalAllocUnicode(ptr);
        }
    }
}

// Defensive copying
public byte[] ProcessSensitiveData(byte[] input)
{
    // Make defensive copy to prevent external modifications
    byte[] workingCopy = (byte[])input.Clone();
    try
    {
        // Process data
        return Transform(workingCopy);
    }
    finally
    {
        // Clear working copy
        CryptographicOperations.ZeroMemory(workingCopy);
    }
}

Examples

JWT Token Generation

public class JwtHelper
{
    private readonly Ed25519PrivateKey signingKey;
    
    public string CreateToken(Dictionary<string, object> claims)
    {
        // Create header
        var header = new { alg = "EdDSA", typ = "JWT" };
        
        // Create payload
        claims["iat"] = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        claims["exp"] = DateTimeOffset.UtcNow.AddHours(1).ToUnixTimeSeconds();
        
        // Encode header and payload
        string encodedHeader = Base64Url.Encode(
            JsonSerializer.SerializeToUtf8Bytes(header));
        string encodedPayload = Base64Url.Encode(
            JsonSerializer.SerializeToUtf8Bytes(claims));
        
        // Create signature
        string message = $"{encodedHeader}.{encodedPayload}";
        byte[] signature = Ed25519.Sign(
            Encoding.UTF8.GetBytes(message), signingKey);
        
        // Return complete JWT
        return $"{message}.{Base64Url.Encode(signature)}";
    }
}

Encrypted File Storage

public class SecureFileStorage
{
    private readonly byte[] masterKey;
    
    public async Task<string> StoreFileAsync(
        string filePath, Stream fileStream)
    {
        // Generate file-specific key
        byte[] fileKey = Blake3.DeriveKey(
            $"file-key:{filePath}", masterKey, 32);
        
        // Generate nonce
        byte[] nonce = RandomNumberGenerator.GetBytes(12);
        
        // Encrypt file
        using var cipher = new ChaCha20Poly1305(fileKey);
        using var output = new MemoryStream();
        
        // Write nonce
        await output.WriteAsync(nonce);
        
        // Encrypt and write chunks
        byte[] buffer = new byte[4096];
        int bytesRead;
        
        while ((bytesRead = await fileStream.ReadAsync(buffer)) > 0)
        {
            var (encrypted, tag) = cipher.Encrypt(
                buffer.AsSpan(0, bytesRead), nonce);
            
            await output.WriteAsync(encrypted);
            await output.WriteAsync(tag);
            
            // Increment nonce for next chunk
            IncrementNonce(nonce);
        }
        
        // Save encrypted file
        string encryptedPath = $"{filePath}.enc";
        await File.WriteAllBytesAsync(encryptedPath, output.ToArray());
        
        return encryptedPath;
    }
}

Testing

Unit Testing

using Xunit;
using MetaMUI.Crypto;

public class CryptoTests
{
    [Fact]
    public void Ed25519_SignAndVerify_Success()
    {
        // Arrange
        var keypair = Ed25519.GenerateKeypair();
        byte[] message = Encoding.UTF8.GetBytes("test message");
        
        // Act
        byte[] signature = Ed25519.Sign(message, keypair.PrivateKey);
        bool isValid = Ed25519.Verify(signature, message, keypair.PublicKey);
        
        // Assert
        Assert.True(isValid);
    }
    
    [Theory]
    [InlineData(16)]
    [InlineData(32)]
    [InlineData(64)]
    public void SecureRandom_GeneratesUniqueBytes(int size)
    {
        // Act
        byte[] random1 = SecureRandom.GetBytes(size);
        byte[] random2 = SecureRandom.GetBytes(size);
        
        // Assert
        Assert.NotEqual(random1, random2);
        Assert.Equal(size, random1.Length);
    }
}

See Also