CryptoCalc — Application Specification

Standalone Non-Custodial Cryptocurrency Wallet Generator

Version 0.5.9 ElectronJS Desktop App 23 Cryptocurrencies BIP32 / BIP39 / BIP38 Windows & Linux

1 Overview & Purpose

CryptoCalc is a non-custodial, standalone desktop application for generating cryptocurrency wallets. It is designed to run entirely offline ("cold wallet" philosophy) so that sensitive cryptographic material — Private Keys, WIF, and Secret phrases — never leaves the user's machine and is never exposed to a remote server.

Wallets can be Non-Deterministic (Simple Wallet) or Hierarchical Deterministic (HD Wallet, BIP32). CryptoCalc supports 23 cryptocurrencies and 18 Secret phrase languages.

Since its first release, CryptoCalc has been downloaded more than 16 552 times on npm.

The application is built with JavaScript / ElectronJS and is available as a standalone installer (Windows) as well as via source clone (Windows & Linux). Wallet output is saved as .wits JSON files under a timestamped _output/ subfolder.

2 Entropy Generation & Sources

All wallet generation starts with a high-quality Entropy value. CryptoCalc provides four distinct entropy sources:

2.1 D6 Dice Rolls (default)

The user rolls virtual six-sided dice. The number of rolls is determined by the chosen Entropy Size (e.g. 100 rolls for 256-bit entropy).

2.2 Mouse Movement

Entropy bytes are captured from the user's mouse pointer movements, providing a non-deterministic physical source.

2.3 Image Drop

The user can drag-and-drop any PNG, JPG, or SVG image onto the application. Pressing [Generate] draws a random cryptocurrency logo from www/img/CryptoCurrency. Sample images are provided in www/img/.

2.4 Fortune Cookies

A corpus of 12 803 quotes is used as a source. A random quote is drawn each time [Generate] is pressed.

2.5 Salted Entropy

Regardless of the source, CryptoCalc combines the raw entropy value with a Salt (a dynamically generated UUID, 128 bits of additional entropy) using SHA-256:

Salted Entropy = SHA256(Salt + Entropy_source_value)

This guarantees uniqueness at every [Generate] press, even when the same image or fortune cookie is reused.

2.6 Entropy Size

The user can choose an entropy size between 128 and 256 bits (32 to 64 hex digits), which corresponds to a Secret phrase of 12 to 24 words. Both representations remain synchronized in real time.

3 Wallet Modes

Three wallet generation modes are available, selectable from the Wallet tab page.

Simple Wallet

Default mode. Each wallet is independent; no BIP32 hierarchy or Derivation Path is involved. Ideal for beginners. Less resistant to dictionary attacks if low-entropy inputs are used.

HD Wallet (BIP32)

Full Hierarchical Deterministic wallet tree. All wallets share the same Secret phrase. Navigation via Account and Address Index fields (0–999 999). Supports BIP44, BIP49, BIP84 purposes.

SWORD Wallet

Simple Wallet Over Randomized Deterministic — a hybrid. Generates all HD-wallet-compatible cryptocurrencies without exposing the BIP32 derivation path complexity to the user.

Special Cases

For Cardano HD wallets, Account and Address Index are hard-coded to 0 to match the behavior of Guarda and Yoroi wallet managers.

Generated HD wallets can be cross-checked with the Ian Coleman BIP39 tool (linked in Help / Resources menu). Remember to enable "Use hardened addresses".

4 BIP39 — Secret Phrase & Word Indexes

4.1 Secret Phrase Generation

Entropy is converted to a BIP39 Secret phrase (also called Mnemonics or Secret Recovery Passphrase) of 12 to 24 words. The conversion appends a checksum (first N bits of SHA256(entropy)) to pad to a multiple of 11 bits, then each 11-bit segment selects a word from the 2048-word BIP39 dictionary.

4.2 Shortened Secret Phrase

Because only the first 4 characters of each BIP39 mnemonic are significant, CryptoCalc derives a Shortened Secret phrase where each word is abbreviated to its first 4 characters (first letter capitalized):

Example (12 words):
Full: rent expand super sea summer pull catalog mobile proud solve oven goose
Short: RentExpaSupeSeaSummPullCataMobiProuSolvOvenGoos

The Shortened Secret phrase is not for importing into a Wallet Manager. Its purpose is compact storage (e.g. on a NTAG213 NFC SmartRing with 144 bytes capacity — 24 words × 4 chars = 96 bytes max).

4.3 Word Indexes Display

Word indexes (0–2047) are displayed alongside the Secret phrase in Decimal or Binary format. In Binary mode, the checksum bits appended to the last word are clearly visible. Word indexes are language-independent — the same entropy yields the same indexes regardless of the chosen wordlist language.

4.4 Dynamic Entropy ↔ Secret Phrase Conversion

Pasting a raw hex entropy value automatically recomputes the Secret phrase, and vice versa.

4.5 BIP39 Passphrase (HD Wallet only)

An optional BIP39 Passphrase (acting as an additional password) shifts the entire BIP32 hierarchy to a completely different tree. To avoid accidental application, the field is readonly by default:

5 BIP32 — HD Wallet & Derivation Path

5.1 Derivation Path

CryptoCalc uses the standard BIP44 derivation path structure: m / purpose' / coin_type' / account' / change / address_index

Example for Ethereum: m/44'/60'/0'/0/0

SegmentMeaning
mMaster key (root of the tree)
44'BIP44 purpose (hardened)
60'Coin type (e.g. 60 = Ethereum)
0'Account (hardened by default)
0External chain (public addresses)
0Address index

5.2 Supported Purposes

5.3 Account & Address Index

Both fields accept decimal values from 0 to 999 999 (6 digits max), giving 1 000 000 possible values each. Editing either field displays a [Refresh] button (also triggered by Enter) to recompute the wallet address.

5.4 Hardened Derivation

Hardened derivation is mandatory and on by default (since v0.3.18) for security: a compromised child key cannot be used to derive sibling or parent keys.

6 BIP38 — Private Key Encryption

CryptoCalc supports BIP38 NON-EC encryption: the Private Key is symmetrically encrypted with a user-supplied passphrase, producing a BIP38 Encrypted Private Key.

6.1 How to Use

  1. Enter a value in the BIP38 Passphrase field.
  2. Press [Save] or use File / Save.
  3. The BIP38 Encrypted PK is computed and saved alongside the wallet.

6.2 BIP38 Encrypt / Decrypt Tool

A dedicated dialog (Tools / BIP38 Encrypt/Decrypt) is provided to:

A progress bar gives visual feedback during the time-consuming scrypt computation.

6.3 Key Use Case

The BIP38 Encrypted PK allows outsourcing paper wallet printing (with premium features: watermark, hologram, embossing…) without disclosing the raw Private Key to the printer. The Passphrase is communicated via a separate channel.

Security: The raw Private Key is still saved in wallet_info.txt. The BIP38 Encrypted PK may be shared in certain use cases; the raw Private Key must never be disclosed, nor should the BIP38 Passphrase.

6.4 QR Code Output

A new QR code for the BIP38 Encrypted PK is generated as both a PNG file and an SVG file (in the xtras/ subfolder).

7 Passphrase Strength Evaluator

A real-time visual indicator evaluates the strength of the BIP39 and BIP38 passphrases using the zxcvbn library (developed by Dropbox). It accounts for dictionary words, common patterns, keyboard walks, and Leetspeak substitutions.

ScoreLabelColor
0Very WeakRed
1WeakOrange
2FairYellow
3GoodGreen
4StrongViolet

The score is displayed as a colored bar (length proportional to score) and a text label. Hovering over the label shows the entropy in bits.

It is strongly recommended to use the [Random] button (circular arrow icon) to generate a passphrase, rather than typing one manually, to avoid predictable patterns.

8 QR Code Generation

QR codes are automatically generated and saved when a wallet is saved. They cover the following data fields:

8.1 Output Formats

8.2 Recovering a Wallet from a Rectangular Micro QR Code

  1. Scan the rMQR with an Android app compatible with rMQR (e.g. QRQR by Arara).
  2. Copy the scanned entropy hex string into CryptoCalc's Entropy field.
  3. Ensure Entropy Size and Derivation Path match those recorded in wallet_info.txt / wallet_info.wits.

9 Save & Open Wallet Informations

9.1 Saving a Wallet

Use File / Save or the Save toolbar icon. A timestamped subfolder is created under _output/ (e.g. 2024_10_07_21h-4m-4s-3_BTC_EN), containing:

A popup dialog confirms saving and offers to open the output folder.

9.2 Opening a Previously Saved Wallet

Use File / Open… or the Open toolbar icon to load a .wits file. On Windows, double-clicking a .wits file launches Cryptocalc.exe and opens it directly (file-extension association).

10 Wallets Database (SQLite)

Via Tools / Database Management, previously saved .wits files can be imported into a local SQLite database. The database can then be explored and queried with an external tool such as DBeaver (which also provides a visual DB schema).

11 Dedicated Tools

11.1 Secret Phrase Translator (Tools / Secret Phrase Translator)

Translates a Secret phrase from one BIP39 language to another. Primary use case: a Secret phrase written in a non-English language (e.g. Russian) must be translated to English before it can be imported into a Wallet Manager.

11.2 BIP38 Encrypt / Decrypt (Tools / BIP38 Encrypt/Decrypt)

Standalone dialog to encrypt a raw Private Key to a BIP38 Encrypted PK, or conversely decrypt a BIP38 Encrypted PK back to the raw Private Key. A progress bar shows the computation progress.

11.3 Options (Tools / Options)

Set persistent defaults for:

Options are stored in www/config/options.json and can be reset to factory defaults (from www/config/defaults/options.json).

13 Internet Connection Status

An icon on the right side of the main toolbar permanently displays the network status:

A text label Online / Offline accompanies the icon. This reinforces the cold-wallet, non-custodial philosophy of the application.

14 Customizable Options

Options (Tools / Options) persist across sessions in www/config/options.json:

OptionValuesDefault
Default BlockchainAny of the 23 supported coinsBTC
Wallet ModeSimple / HD / SWORDSimple
Entropy Size128 / 160 / 192 / 224 / 256 bits256 bits

A Reset to Defaults action restores the values from www/config/defaults/options.json.

15 Localization (L10n)

GUI labels are translated to the user's system language via JSON localization files located in www/js/L10n/. The locale is determined from the host OS environment (2-letter ISO code, e.g. en, fr).

16 Supported Cryptocurrencies (23)

CryptoCalc supports wallet generation for the following 23 cryptocurrencies:

BTC — Bitcoin ETH — Ethereum XRP — Ripple BNB — Binance Smart Chain SOL — Solana DOGE — Dogecoin TRX — TRON ADA — Cardano XLM — Stellar SUI — Sui BCH — Bitcoin Cash AVAX — Avalanche TON — Toncoin LTC — Litecoin ETC — Ethereum Classic POL — Polygon VET — VeChain BSV — Bitcoin SV DASH — Dash RVN — Ravencoin ZEN — Horizen LUNA — Terra 2.0 FIRO — Firo

Notes: BNB is on Binance Smart Chain (BEP-20 token). LUNA is LUNA 2.0 (Terra blockchain), not LUNA Classic. SUI support was validated with the Suiet Chrome extension. BIP84 (native SegWit) is available only for BTC and LTC. A list of the top-50 market-cap coins with CryptoCalc support indicators is provided in _doc/top_50_marketcap_coins.txt.

17 Supported Secret Phrase Languages (18)

17.1 Official BIP39 Languages (10)

English French Spanish Italian Czech Portuguese Simplified Chinese Traditional Chinese Japanese Korean

Only English is accepted by hardware wallets (Ledger, Trezor) and most software wallet managers.

17.2 Non-Official Languages (8)

Deutsch Russian Esperanto Latin Greek Hindi Gujarati Bengali

Using a non-English language is an obfuscation layer: the Secret phrase must be translated back to English (via the Secret Phrase Translator tool) before it can be imported into a Wallet Manager. The reference data is always the Word Indexes, which are language-independent.

18 Security Considerations

Critical: Never disclose the Private Key. In the BIP38 Encryption use case, never share both the BIP38 Encrypted PK and the BIP38 Passphrase through the same channel.

18.1 Cold Wallet Philosophy

CryptoCalc is designed to be used offline. The Internet Connection Status indicator warns the user when the machine is online. Generating wallets while connected to the Internet is actively discouraged.

18.2 Hardened BIP32 Derivation

HD wallets use hardened derivation by default, preventing a compromised child key from being used to derive sibling or parent keys.

18.3 BIP38 Additional Layer

The Private Key can be encrypted with a BIP38 Passphrase, adding a second layer of protection if the wallet file is ever exposed (see §6).

18.4 Language Obfuscation

Storing the Secret phrase in a non-English language makes it unusable without knowledge of the language used. Combined with the BIP39 Passphrase, this provides a multi-layer security approach.

18.5 NFC SmartRing Storage

The Shortened Secret phrase (max 96 bytes for 24 words) can be stored on an entry-level NTAG213 NFC SmartRing (144 bytes usable capacity), providing a wearable physical backup.

19 Setup & Installation

19.1 Standalone Installer (recommended for end users)

Download the installer from SourceForge. Generated with electron packager and Inno Setup.

19.2 Source Clone — Windows

Prerequisites: NodeJS, Git

git clone https://github.com/ALADAS-org/cryptocalc.git
cd cryptocalc
npm install
_runW.bat        # or: npm start

19.3 Source Clone — Linux (tested on Linux Mint 22.2)

Prerequisites: NodeJS, Git, npm, xdg-utils

sudo apt-get install nodejs git npm xdg-utils
git clone https://github.com/ALADAS-org/Cryptocalc.git
cd Cryptocalc
npm install
chmod 777 ./_runX.sh
./_runX.sh        # or: npm start

20 Unit Tests (Jest)

Unit tests use the Jest framework (ongoing effort since v0.5.4). They run in a Node.js environment (no browser / Electron renderer required) and cover cryptographic utilities, wallet generators, and general-purpose helpers.

20.1 Running the Tests

npm test                          # run all Jest unit tests
npx jest <path/to/file.test.js>   # run a single file
npm run test:jest:watch           # watch mode
npm run test:jest:coverage        # with HTML coverage report

The HTML coverage report is generated at tests/coverage/jest/test-report.html.
Coverage thresholds: ≥ 70% for all four metrics (branches, functions, lines, statements).

20.2 Configuration (jest.config.js)

SettingValue
Test environmentNode.js
Timeout10 000 ms
Test roottests/jest/
Workers50% of available CPUs
Coverage reporterstext, text-summary, lcov, html, json, cobertura
HTML test reporttests/coverage/jest/test-report.html (via jest-html-reporter)

20.3 Module Aliases

AliasResolved path
@/www/
@crypto/www/js/crypto/
@api/www/js/api/
@util/www/js/util/
@tests/tests/jest/
@fixtures/tests/jest/fixtures/

20.4 Global Test Setup (tests/jest/setup.js)

Provides shared helpers and custom matchers available to all test files:

Helper functions

  • loadFixture(filename) — load JSON from fixtures/inputs/
  • loadExpected(filename) — load JSON from fixtures/expected/
  • saveFixture(filename, data, type) — persist fixture files

Custom Jest matchers

  • toBeValidHash(length) — validates a hex string of exact length
  • toBeValidBitcoinAddress() — legacy, P2SH & SegWit formats
  • toBeValidWIF() — WIF private key format
  • toBeValidEthereumAddress() — checksummed ETH address
  • toBeValidMnemonic() — 12/15/18/21/24-word BIP39 phrase

20.5 Test File Inventory

FileScopeKey tested functions# tests
crypto/bip39_utils.test.js BIP39 core EntropyToMnemonics, MnemonicsToEntropyInfo, GetWordIndexes, GuessMnemonicsLang, CheckMnemonics, MnemonicsAs4letter, GetBIP39Dictionary… 77
crypto/bip39_extras.test.js BIP39 extras PrivateKeyToMnemonics, MnemonicsAs4letter, MnemonicsAsTwoParts, LabelWithSize 32
crypto/bip32_utils.test.js BIP32 / HD Wallet MnemonicsToHDWalletInfo (BTC/ETH/+), GetDerivationPath, account & address index derivation, BIP39 passphrase, BIP44/49/84 purposes, reference vectors 112
crypto/bip38_utils.test.js BIP38 encryption encrypt(), decrypt(), scrypt params, round-trip, wrong passphrase, progress callback (bip38 mocked) 79
crypto/crypto_services.test.js CryptoServices singleton getUUID() (UUID v4 format), pk2WIF(), singleton pattern ~15
crypto/entropy_size.test.js Entropy ↔ size helpers GetBitCount, GetWordCount, GetExpectedWordCount, GetChecksumBitCount, GetSHA256Substring 29
crypto/password_strength_evaluator.test.js Passphrase strength is_binary_string, is_hexa_string, is_base58/64/octal, getPasswordStrengthAsBits, getPasswordStrengthScore (zxcvbn), getPasswordStrengthInfo 79
crypto/base58_utils.test.js Base58 encoding isBase58String, hexToB58, b58ToHex, round-trip, alphabet validation 18
utils/hex_utils.test.js Hex utilities hexWithPrefix/WithoutPrefix, isHexString, hexToBinary, hexToUint8Array, hexToB64, getRandomHexValue, round-trips 43
utils/number_utils.test.js Number helpers stringToInt, stringToFloat, valueIsNumber, stringIsNumber 28
utils/string_utils.test.js String helpers isString, stringify (circular ref), insertAfterEveryN, stringToHex, getShortenedString, asTwoParts 35
wallet/address_validation.test.js Address formats Bitcoin (legacy/P2SH/SegWit), Ethereum checksummed, WIF (compressed/uncompressed), BIP39 mnemonic (12/24 words) 8
wallet/simple_wallet.test.js Simple Wallet generation Wallet structure for BTC, ETH, DOGE, LTC, SOL, AVAX, POL, TON, LUNA, ZEN — validates address, private key, public key, mnemonics, wallet mode 10+
smoke.test.js Jest config sanity TEST_MODE global, CRYPTO_CONFIG (SUPPORTED_COINS, ENTROPY_SIZES), TEST_PATHS 4

20.6 Known Reference Vectors (BIP32)

The BIP32 tests include deterministic reference checks with known expected values (account=2, address_index=5, passphrase="my secret passphrase"):

CoinAddressPrivate Key (prefix)
Bitcoin 1BQQ4VjXtPGd3YEV45vuMkNKjo42pjLLUB ca2dc38… / WIF L3ziiGb…
Ethereum 0x67C0ae27e79Ba1B6f58af5DCF3d893f7394ac0e5 cfe5210…

21 E2E Tests (Playwright)

End-to-end tests launch the full Electron application and interact with it programmatically via Playwright. They validate complete user workflows — from entropy generation to wallet save/reload.

21.1 Running the Tests

npm run test:playwright          # headless
npm run test:playwright:ui       # interactive Playwright UI
npm run test:playwright:debug    # step-by-step debugger

21.2 Configuration (tests/playwright/playwright.config.js)

SettingValue
Test directorytests/playwright/e2e/
Workers1 (Electron limitation — no parallel tests)
Retries on failure2
Test timeout30 s
Action timeout10 s
Navigation timeout30 s
Screenshots/Videos/TracesOnly on failure
ReportHTML — tests/playwright/playwright-report/
Raw resultstests/playwright/test-results/

21.3 Custom Fixtures & Helpers (tests/playwright/setup.js)

Fixtures

  • electronApp — launches www/js/_main/electron_main.js
  • page — waits for DOM content loaded
  • appScreenshot — timestamped screenshots

Helper functions

  • waitForAppReady(page) — DOM ready + 3 s Electron init delay
  • loadFixture(filename) — loads JSON from fixtures/

21.4 E2E Test Scenarios

Scenario 1 — Bitcoin HD Wallet (hd_wallet_usecase.test.js)

Tests BIP32 HD wallet derivation for Bitcoin with fixed, reproducible input data (fixed salt + entropy, account=2, address_index=5).

Test caseWhat is verified
Bitcoin address validityDerived address matches legacy/P2SH/Bech32 regex
BIP39 passphrase effectSame account/index with different passphrase → different address

Page interaction helpers used: switchToHDWallet, deriveFromFixedEntropy, setBip39Passphrase, clickRefresh, getDisplayedAddress, setFieldValue.

Scenario 2 — Dogecoin HD Wallet Save/Load/Update (dogecoin_hd_wallet_usecase.test.js)

Tests the complete wallet lifecycle for Dogecoin HD wallets.

StepActionAssertion
1Select Dogecoin, HD mode, account=1, index=3Address generated and displayed
2Save wallet (/tmp/cryptocalc_test_doge_1.json, dialogs mocked)File written successfully
3Open saved .wits fileAddress and fields reload correctly
4Change account → 4, address index → 7, press [Refresh]New address is different from original
5Save As (/tmp/cryptocalc_test_doge_2.json)Second file contains updated address

Page interaction helpers used: switchToHDWallet, selectBlockchain, setFieldValue.

Playwright test protocols are documented in tests/playwright/_doc/hd_wallet_usecase_test_protocols.html.

22 Technology Stack

Runtime

  • ElectronJS ≤ 31 (pinned — later versions block dropped file paths)
  • Node.js — main process & test runner
  • JavaScript — both renderer and main process

Crypto Libraries

  • bs58 v5.0.0 (pinned — ESM incompatibility in v6+)
  • ed25519-hd-key, @mysten/sui, @ton/crypto
  • zxcvbn — passphrase strength
  • cashaddrjs — Bitcoin Cash address encoding

Testing

  • Jest — unit tests (344 tests in v0.5.9)
  • Playwright — E2E tests
  • Coverage report at tests/coverage/jest/test-report.html
  • Coverage threshold: ≥ 70% for all four metrics

Build & Distribution

  • electron packager — produces the distributable app
  • Inno Setup — Windows installer
  • Published on SourceForge and npm
  • SQLite via better-sqlite3 for wallet database

Architecture Overview

LayerEntry Point / Key FileRole
Main Processwww/js/_main/electron_main.jsBrowserWindow, IPC, file I/O, menus
Preloadwww/js/_main/preload.jsSafe IPC bridge to renderer
Rendererwww/index.htmlUI entry point
Cryptowww/js/crypto/BIP32/39/38, wallet generators
Viewwww/js/view/main_gui.jsMainGUI singleton, dialogs
Modelwww/js/model/QR codes, wallet persistence, SQLite
Utilswww/js/util/Logging, HTML helpers, value utils
L10nwww/js/L10n/GUI label translations (JSON)