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
- .NET Framework 4.6.1+
- .NET Core 2.0+
- .NET 5.0+
- .NET 6.0+
- .NET 7.0+
- .NET 8.0+
- Unity 2019.4+
- Xamarin
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);
}
}