branevault
v1.0.7
Published
Memory-hard deterministic key derivation from human-memorable credentials
Maintainers
Readme
BrainVault
Memory-hard deterministic key derivation from human-memorable credentials.
⚠️ CRITICAL: AIR-GAP MANDATORY
This tool generates cryptocurrency keys. Run ONLY on air-gapped machines. NEVER run on internet-connected devices. Compromised keys mean PERMANENT FUND LOSS.
⚠️ NOT AUDITED - BETA SOFTWARE
This software and its dependencies (including @noble/post-quantum) have NOT been professionally audited. This is v1.0.0 - first public release. Use ONLY small test amounts until community review and professional audit.
✓ BEFORE FUNDING: TEST CREDENTIAL RECALL
Forgotten credentials mean permanent fund loss. Before sending any funds:
- Generate keys and save receipt
- Verify you can reproduce the fingerprint 5-10 times over several days
- Start with small test amounts ($10-100)
- Only increase amounts after successful recall testing
What It Does
BrainVault derives deterministic post-quantum cryptographic keys from:
- An identity (email/username)
- A master password
- Configurable security parameters
It outputs:
- A SLH-DSA-SHAKE-256s keypair (NIST FIPS 205, post-quantum secure)
- A high-entropy Base58 password (for legacy applications)
- A 24-word BIP39 mnemonic (optional, for existing cryptocurrency infrastructure)
Why Memory-Hard?
Traditional brain wallets are vulnerable to brute-force attacks. BrainVault uses Argon2id with aggressive memory requirements (64MB-1GB per hash) and parallel lane saturation. This forces attackers to use substantial RAM per guess, making large-scale attacks economically impractical.
Installation
# Global installation (for CLI)
npm install -g brainvault
# Or run directly with npx
npx brainvault
# As a dependency
npm install brainvaultCLI Usage
Generate Keys
# Interactive mode
npx brainvault
# With receipt (re-hydrates previous settings)
npx brainvault --receipt ./my-receipt.jsonVerify Credentials
# Verify you can reproduce the same fingerprint
npx brainvault-verify ./my-receipt.json
# Manual parameter entry
npx brainvault-verify --manualProgrammatic Usage
import { deriveKeys, createConfig, Profile } from 'brainvault';
const config = createConfig({
identity: '[email protected]',
password: Buffer.from('my-secure-password'),
profile: Profile.Standard,
generation: 0,
factor: 3,
outputMode: 'pq', // 'pq' | 'legacy' | 'both'
});
const result = await deriveKeys(config, {
onProgress: (current, total) => {
console.log(`Progress: ${current}/${total}`);
},
});
// Post-quantum keys (primary output)
console.log(result.pq.secretKey); // 128-byte SLH-DSA secret key
console.log(result.pq.publicKey); // 64-byte SLH-DSA public key
// Legacy outputs (when outputMode is 'legacy' or 'both')
console.log(result.legacy?.mnemonic); // 24-word BIP39 phrase
console.log(result.legacy?.appPassword); // Base58 password
console.log(result.fingerprint); // 12-char verification fingerprint
// IMPORTANT: Zero sensitive buffers when done
result.zero();Security Profiles
| Profile | Memory | Threads | Use Case | |---------|--------|---------|----------| | Portable | 64 MB | 1 | Travel/low-spec devices | | Standard | 256 MB | 4 | Desktop computers | | Bunker | 1 GB | 8 | Cold storage, maximum security |
Time Factor Guide
| Factor | Base Shards | Approx. Time (Standard) | |--------|-------------|-------------------------| | 1 | 16 | ~5 seconds | | 3 | 64 | ~20 seconds | | 5 | 256 | ~2 minutes | | 7 | 1024 | ~8 minutes | | 9 | 4096 | ~30 minutes |
Weak passwords incur additional penalty shards (up to 2048 extra).
Password Strength
BrainVault analyzes password strength and applies penalties:
| Entropy (log10) | Penalty | Assessment | |-----------------|---------|------------| | < 12 | BLOCKED | Too weak, cannot proceed | | 12-14 | +2048 shards | Weak | | 14-18 | +512 shards | Moderate | | 18+ | None | Strong |
Receipt Files
After generation, a receipt JSON is saved containing:
- Partial email hash (for verification)
- Profile, generation, factor settings
- Fingerprint (for credential recall testing)
- NO secrets
Use receipts to:
- Re-hydrate settings on future runs
- Verify you remember credentials correctly
- Document your setup (store separately from passwords)
Algorithm Details
1. Salt = SHA3-256(emailHash | shardIndex | generation | ALG_TAG)
2. For each shard i in [0, totalShards):
shardOutput[i] = Argon2id(password, salt_i, memCost, timeCost=2, parallelism)
3. masterIKM = SHA3-512(header | shard[0] | shard[1] | ... | shard[n])
4. slhDsaSeed = HKDF-SHA512(masterIKM, context="BrainVault-v3-SLH-DSA-SHAKE-256s-Seed", 96 bytes)
5. (secretKey, publicKey) = SLH-DSA-SHAKE-256s-KeyGen(slhDsaSeed)
6. [Optional] mnemonicEntropy = HKDF-SHA512(masterIKM, context="BrainVault-v3-BIP39-Mnemonic", 32 bytes)
7. [Optional] passwordEntropy = HKDF-SHA512(masterIKM, context="BrainVault-v3-Base58-Password", 64 bytes)Full specification: See ALGORITHM.md
Critical Limitations
This is beta software. Do NOT use for amounts you cannot afford to lose.
Unaudited Dependencies
BrainVault uses @noble/post-quantum for SLH-DSA signatures. This library:
- Has NOT been professionally audited
- Is version 0.x (pre-stable API)
- Is the foundation of all post-quantum security claims
If @noble/post-quantum has bugs, your keys are compromised regardless of password strength.
JavaScript Memory Model
JavaScript cannot guarantee secure memory handling:
zeroBuffer()callsbuf.fill(0)but V8 may retain copies in memory- Garbage collection timing is unpredictable
- Old buffer contents may persist in heap memory after cleanup
- String passwords are interned by JavaScript and cannot be zeroed
- Hot-path JIT optimizations may create additional copies
Mitigation: Reboot the machine after key generation to clear RAM. Use air-gapped dedicated hardware.
Beta Software (v1.0.0)
This is the first public release. Treat it as beta:
- Start with small test amounts - Send $10-100 maximum until community review
- Test credential recall BEFORE funding - Verify you can reproduce fingerprint multiple times
- Wait for professional audit before using for significant amounts
- Report issues at github.com/adimov-eth/brainvault
What Could Go Wrong
| Risk | Impact | Mitigation | |------|--------|------------| | Password forgotten | Total fund loss | Use memorable passphrase, test recall extensively before funding | | Unicode normalization bug | Wrong keys derived | Now mitigated via NFC normalization, but test on your actual OS/keyboard | | @noble/post-quantum bug | Key compromise | Wait for audit, use small amounts only | | Air-gap violated | Key theft | Dedicated offline machine, never connect to network | | Receipt lost | Cannot verify settings | Can re-derive if you remember all parameters, back up receipt securely | | JavaScript memory leak | Sensitive data exposure | Reboot after generation, use dedicated hardware | | Implementation bug | Incorrect keys/loss | Test with small amounts first, wait for community review |
Recommended Usage
Test phase (current):
- Generate keys on air-gapped machine
- Send small test amount ($10-100)
- Practice credential recall 5-10 times over several days
- Verify fingerprint matches receipt each time
- Only increase amount after successful recall testing
Production phase (after audit):
- Commission independent security audit
- Verify audit findings
- Use bunker profile on dedicated hardware
- Consider multi-signature schemes for large amounts
Security Considerations
- Air-gap is mandatory - Never run on networked machines. Compromised keys mean lost funds.
- Password entropy matters - Memory-hardness helps but doesn't fix weak passwords. Use 20+ character passphrases with mixed character types.
- Test recall before funding - Verify you can reproduce the exact fingerprint multiple times over several days before sending any funds.
- Receipts are not secrets - But store them separately from passwords. Loss means you need to remember all parameters manually.
- Generation for rotation - Increment generation parameter if you suspect compromise.
- Buffer zeroing is best-effort - JavaScript/V8 GC limitations mean sensitive data may persist. Reboot after generation.
API Reference
deriveKeys(config, options?)
Main derivation function.
interface DerivationConfig {
identity: string;
password: Buffer;
profile: Profile;
generation: number;
factor: number;
outputMode: 'pq' | 'legacy' | 'both';
}
interface DerivationOptions {
onProgress?: (current: number, total: number) => void;
}
interface DerivationResult {
pq?: {
secretKey: Buffer; // 128 bytes
publicKey: Buffer; // 64 bytes
keypair: Buffer; // 192 bytes (concatenated)
};
legacy?: {
mnemonic: string; // 24-word BIP39 phrase
appPassword: string; // Base58 password
};
fingerprint: string;
totalShards: number;
zero: () => void; // Call to zero internal buffers
}analyzePassword(password, userInputs?)
Analyze password strength.
interface PasswordAnalysis {
guessesLog10: number;
penaltyShards: number;
reason: string;
isUnsafe: boolean;
}verifyFingerprint(config, expectedFingerprint, options?)
Verify credentials match expected fingerprint.
interface VerificationResult {
matches: boolean;
computedFingerprint: string;
expectedFingerprint: string;
}License
MIT
