Crypto Module
The Ton.Crypto module provides cryptographic primitives for TON blockchain: Ed25519 signatures, mnemonic phrases, and hashing functions.
Features
- ✅ BIP39 Mnemonics - TON-specific mnemonic generation and validation
- ✅ Ed25519 - Signing and verification
- ✅ Hashing - SHA-256, SHA-512, HMAC-SHA512
- ✅ Key Derivation - PBKDF2-SHA512
- ✅ Secure Random - Cryptographically secure RNG
Mnemonics
TON uses BIP39-compatible mnemonics with TON-specific validation.
Generate Mnemonic
using Ton.Crypto.Mnemonic;
// Generate 24-word mnemonic (recommended)
string[] mnemonic = Mnemonic.New(24);
// Generate 12-word mnemonic
string[] shortMnemonic = Mnemonic.New(12);
// With password protection
string[] protectedMnemonic = Mnemonic.New(24, password: "my-secure-password");
// Display to user
Console.WriteLine(string.Join(" ", mnemonic));
Validate Mnemonic
string[] mnemonic = GetMnemonicFromUser();
// Validate without password
if (Mnemonic.Validate(mnemonic))
{
Console.WriteLine("✓ Valid mnemonic");
}
else
{
Console.WriteLine("✗ Invalid mnemonic");
}
// Validate with password
if (Mnemonic.Validate(mnemonic, password: "my-secure-password"))
{
Console.WriteLine("✓ Valid mnemonic with password");
}
Derive Keys
using Ton.Crypto.Ed25519;
// Get wallet key pair (for signing transactions)
KeyPair walletKeys = Mnemonic.ToWalletKey(mnemonic);
byte[] publicKey = walletKeys.PublicKey; // 32 bytes
byte[] secretKey = walletKeys.SecretKey; // 64 bytes (private + public)
// Get private key (master key)
KeyPair privateKey = Mnemonic.ToPrivateKey(mnemonic);
// Get HD seed (for hierarchical deterministic wallets)
byte[] hdSeed = Mnemonic.ToHdSeed(mnemonic); // 64 bytes
Mnemonic to Address
using Ton.Contracts.Wallets;
using Ton.Core.Addresses;
// Generate mnemonic
string[] mnemonic = Mnemonic.New(24);
// Get wallet keys
KeyPair keys = Mnemonic.ToWalletKey(mnemonic);
// Create wallet contract
WalletV4R2 wallet = new(keys.PublicKey);
Address address = wallet.Address;
Console.WriteLine($"Mnemonic: {string.Join(" ", mnemonic)}");
Console.WriteLine($"Address: {address}");
Mnemonic from Seed
Create deterministic mnemonic from seed:
byte[] randomSeed = new byte[32];
using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
rng.GetBytes(randomSeed);
string[] mnemonic = Mnemonic.FromRandomSeed(randomSeed, 24);
Convert to Entropy
// Get 64-byte entropy from mnemonic
byte[] entropy = Mnemonic.ToEntropy(mnemonic);
// With password
byte[] entropyWithPassword = Mnemonic.ToEntropy(mnemonic, password: "secret");
Convert to Seed
// Get seed for specific purpose
byte[] tonSeed = Mnemonic.ToSeed(mnemonic, "TON default seed");
byte[] hdSeed = Mnemonic.ToSeed(mnemonic, "TON HD Keys seed");
// With password
byte[] protectedSeed = Mnemonic.ToSeed(
mnemonic,
"TON default seed",
password: "secret"
);
Ed25519
Digital signatures using Ed25519.
Generate Key Pair
using Ton.Crypto.Ed25519;
// Generate random key pair
KeyPair keys = Ed25519.GenerateKeyPair();
byte[] publicKey = keys.PublicKey; // 32 bytes
byte[] secretKey = keys.SecretKey; // 64 bytes
Key Pair from Seed
// Deterministic key pair from 32-byte seed
byte[] seed = new byte[32];
// ... fill seed ...
KeyPair keys = Ed25519.KeyPairFromSeed(seed);
Sign Message
KeyPair keys = Ed25519.GenerateKeyPair();
byte[] message = Encoding.UTF8.GetBytes("Hello TON");
// Sign
byte[] signature = Ed25519.Sign(message, keys.SecretKey);
// signature is 64 bytes
Console.WriteLine($"Signature: {Convert.ToBase64String(signature)}");
Verify Signature
byte[] message = Encoding.UTF8.GetBytes("Hello TON");
byte[] signature = ...; // 64 bytes
byte[] publicKey = ...; // 32 bytes
// Verify
bool isValid = Ed25519.Verify(signature, message, publicKey);
if (isValid)
{
Console.WriteLine("✓ Signature valid");
}
else
{
Console.WriteLine("✗ Signature invalid");
}
Extract Public Key
byte[] secretKey = ...; // 64 bytes
// Extract public key from secret key
byte[] publicKey = Ed25519.ExtractPublicKey(secretKey); // 32 bytes
Hashing
Cryptographic hash functions.
SHA-256
using Ton.Crypto.Primitives;
byte[] data = Encoding.UTF8.GetBytes("Hello TON");
// Compute hash
byte[] hash = Sha256.Hash(data); // 32 bytes
Console.WriteLine($"SHA-256: {Convert.ToHexString(hash)}");
SHA-512
byte[] data = Encoding.UTF8.GetBytes("Hello TON");
// Compute hash
byte[] hash = Sha512.Hash(data); // 64 bytes
Console.WriteLine($"SHA-512: {Convert.ToHexString(hash)}");
HMAC-SHA512
byte[] message = Encoding.UTF8.GetBytes("Hello TON");
byte[] key = Encoding.UTF8.GetBytes("secret-key");
// Compute HMAC
byte[] hmac = HmacSha512.Hash(message, key); // 64 bytes
Console.WriteLine($"HMAC-SHA512: {Convert.ToHexString(hmac)}");
PBKDF2-SHA512
Key derivation function:
byte[] password = Encoding.UTF8.GetBytes("my-password");
byte[] salt = Encoding.UTF8.GetBytes("salt");
int iterations = 100000;
int keyLength = 64;
// Derive key
byte[] derivedKey = Pbkdf2Sha512.DeriveKey(password, salt, iterations, keyLength);
Console.WriteLine($"Derived key: {Convert.ToHexString(derivedKey)}");
Secure Random
Cryptographically secure random number generation:
using Ton.Crypto.Primitives;
// Random integer in range [min, max)
int randomNum = SecureRandom.GetNumber(0, 100);
// Random bytes
byte[] randomBytes = new byte[32];
SecureRandom.GetBytes(randomBytes);
NaCl SecretBox
Authenticated encryption:
using Ton.Crypto.Primitives;
byte[] message = Encoding.UTF8.GetBytes("Secret message");
byte[] key = new byte[32]; // 256-bit key
byte[] nonce = new byte[24]; // 192-bit nonce
// Fill key and nonce
SecureRandom.GetBytes(key);
SecureRandom.GetBytes(nonce);
// Encrypt
byte[] ciphertext = SecretBox.Seal(message, nonce, key);
// Decrypt
byte[] decrypted = SecretBox.Open(ciphertext, nonce, key);
string result = Encoding.UTF8.GetString(decrypted);
Console.WriteLine($"Decrypted: {result}");
Practical Examples
Create and Sign Transaction
using Ton.Crypto.Mnemonic;
using Ton.Crypto.Ed25519;
using Ton.Crypto.Primitives;
using Ton.Core.Boc;
// Get keys from mnemonic
string[] mnemonic = GetMnemonicFromUser();
KeyPair keys = Mnemonic.ToWalletKey(mnemonic);
// Create transaction data
Builder builder = Builder.BeginCell();
builder.StoreUint(0, 32); // seqno
// ... more transaction data
Cell cell = builder.EndCell();
byte[] cellHash = cell.Hash(0);
// Sign transaction hash
byte[] signature = Ed25519.Sign(cellHash, keys.SecretKey);
// Build signed message
Builder signedBuilder = Builder.BeginCell();
signedBuilder.StoreBuffer(signature);
signedBuilder.StoreSlice(cell.BeginParse());
Cell signedCell = signedBuilder.EndCell();
Verify Contract Signature
// Extract signature and data from cell
Slice slice = cell.BeginParse();
byte[] signature = slice.LoadBuffer(64);
Cell dataCell = slice.LoadRef();
// Get message hash
byte[] messageHash = dataCell.Hash(0);
// Verify
bool isValid = Ed25519.Verify(signature, messageHash, publicKey);
Password-Protected Wallet
// Create wallet with password
string password = GetPasswordFromUser();
string[] mnemonic = Mnemonic.New(24, password: password);
// Later: recover wallet
string[] recoveredMnemonic = GetMnemonicFromUser();
string recoveredPassword = GetPasswordFromUser();
if (!Mnemonic.Validate(recoveredMnemonic, password: recoveredPassword))
{
Console.WriteLine("Invalid mnemonic or password");
return;
}
KeyPair keys = Mnemonic.ToWalletKey(recoveredMnemonic, password: recoveredPassword);
Key Derivation Path (Custom)
// Get HD seed
byte[] hdSeed = Mnemonic.ToHdSeed(mnemonic);
// Derive child key using PBKDF2
byte[] childSeed = Pbkdf2Sha512.DeriveKey(
hdSeed,
Encoding.UTF8.GetBytes("m/44'/607'/0'/0/0"), // BIP44 path
1,
32
);
KeyPair childKeys = Ed25519.KeyPairFromSeed(childSeed);
Security Best Practices
1. Never Expose Private Keys
// ✅ Good: Keep keys in memory only
KeyPair keys = Mnemonic.ToWalletKey(mnemonic);
// Use keys
Array.Clear(keys.SecretKey, 0, keys.SecretKey.Length); // Clear after use
// ❌ Never: Log or save private keys
Console.WriteLine($"Private key: {Convert.ToBase64String(keys.SecretKey)}"); // DON'T!
File.WriteAllText("key.txt", Convert.ToBase64String(keys.SecretKey)); // DON'T!
2. Validate User Input
// ✅ Good: Always validate mnemonics
string[] userMnemonic = GetMnemonicFromUser();
if (!Mnemonic.Validate(userMnemonic))
{
throw new ArgumentException("Invalid mnemonic");
}
3. Use Secure Storage
// ✅ Good: Use system keychain/credential manager
// Example with .NET Data Protection API
using System.Security.Cryptography;
using Microsoft.AspNetCore.DataProtection;
IDataProtector protector = dataProtectionProvider.CreateProtector("MnemonicStorage");
string encryptedMnemonic = protector.Protect(string.Join(" ", mnemonic));
// Store encryptedMnemonic
// Later: decrypt
string decryptedMnemonic = protector.Unprotect(encryptedMnemonic);
4. Clear Sensitive Data
// ✅ Good: Clear sensitive data from memory
byte[] secretKey = keys.SecretKey;
try
{
// Use secret key
byte[] signature = Ed25519.Sign(message, secretKey);
}
finally
{
// Clear from memory
Array.Clear(secretKey, 0, secretKey.Length);
}
5. Use Strong Passwords
// ✅ Good: Enforce password requirements
string password = GetPasswordFromUser();
if (password.Length < 12)
throw new ArgumentException("Password must be at least 12 characters");
if (!HasUpperCase(password) || !HasNumber(password))
throw new ArgumentException("Password must contain uppercase and numbers");
string[] mnemonic = Mnemonic.New(24, password: password);
6. Verify Signatures
// ✅ Good: Always verify signatures before trusting data
if (!Ed25519.Verify(signature, message, publicKey))
{
throw new SecurityException("Invalid signature");
}
// Only use message after verification
Common Patterns
Mnemonic Import/Export
// Export (display to user)
string mnemonicString = string.Join(" ", mnemonic);
Console.WriteLine($"Write down your recovery phrase:");
Console.WriteLine(mnemonicString);
// Import (from user input)
string userInput = Console.ReadLine();
string[] importedMnemonic = userInput!.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (!Mnemonic.Validate(importedMnemonic))
{
Console.WriteLine("Invalid mnemonic");
return;
}
Key Rotation
// Generate new keys
string[] newMnemonic = Mnemonic.New(24);
KeyPair newKeys = Mnemonic.ToWalletKey(newMnemonic);
// Create new wallet contract
WalletV4R2 newWallet = new(newKeys.PublicKey);
// Transfer funds from old wallet to new wallet
// ... (see Contracts module)