diff --git a/README.md b/README.md index d2e7761..6642e35 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,224 @@ -# React + TypeScript + Vite +# SeedPGP v1.1.0 -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +**Secure BIP39 mnemonic backup using PGP encryption and QR codes** -Currently, two official plugins are available: +A TypeScript/Bun tool for encrypting cryptocurrency seed phrases with OpenPGP and encoding them as QR-friendly Base45 frames with CRC16 integrity checking. -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh +## Features -## React Compiler +- ๐Ÿ” **PGP Encryption**: Uses cv25519 (Curve25519) for modern elliptic curve cryptography +- ๐Ÿ“ฑ **QR Code Ready**: Base45 encoding optimized for QR code generation +- โœ… **Integrity Checking**: CRC16-CCITT-FALSE checksums prevent corruption +- ๐Ÿ”‘ **BIP39 Support**: Full support for 12/18/24-word mnemonics with passphrase indicator +- ๐Ÿงช **Battle-Tested**: Validated against official Trezor BIP39 test vectors +- โšก **Fast**: Built with Bun runtime for optimal performance -The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). +## Installation -## Expanding the ESLint configuration +```bash +# Clone repository +git clone https://github.com/kccleoc/seedpgp-web.git +cd seedpgp-web -If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: +# Install dependencies +bun install -```js -export default defineConfig([ - globalIgnores(['dist']), - { - files: ['**/*.{ts,tsx}'], - extends: [ - // Other configs... +# Run tests +bun test - // Remove tseslint.configs.recommended and replace with this - tseslint.configs.recommendedTypeChecked, - // Alternatively, use this for stricter rules - tseslint.configs.strictTypeChecked, - // Optionally, add this for stylistic rules - tseslint.configs.stylisticTypeChecked, - - // Other configs... - ], - languageOptions: { - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - // other options... - }, - }, -]) +# Start development server +bun run dev ``` -You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: +## Usage -```js -// eslint.config.js -import reactX from 'eslint-plugin-react-x' -import reactDom from 'eslint-plugin-react-dom' +### Encrypt a Mnemonic + +```typescript +import { encryptToSeedPgp, buildPlaintext } from "./lib/seedpgp"; + +const mnemonic = "legal winner thank year wave sausage worth useful legal winner thank yellow"; +const plaintext = buildPlaintext(mnemonic, false); // false = no BIP39 passphrase used + +const result = await encryptToSeedPgp({ + plaintext, + publicKeyArmored: yourPgpPublicKey, +}); + +console.log(result.framed); // SEEDPGP1:0:ABCD:BASE45DATA... +console.log(result.recipientFingerprint); // Key fingerprint for verification +``` + +### Decrypt a SeedPGP Frame + +```typescript +import { decryptSeedPgp } from "./lib/seedpgp"; + +const decrypted = await decryptSeedPgp({ + frameText: "SEEDPGP1:0:ABCD:BASE45DATA...", + privateKeyArmored: yourPrivateKey, + privateKeyPassphrase: "your-key-password", +}); + +console.log(decrypted.w); // Recovered mnemonic +console.log(decrypted.pp); // BIP39 passphrase indicator (0 or 1) +``` + +## Frame Format + +``` +SEEDPGP1:FRAME:CRC16:BASE45DATA + +SEEDPGP1 - Protocol identifier and version +0 - Frame number (0 = single frame) +ABCD - 4-digit hex CRC16-CCITT-FALSE checksum +BASE45 - Base45-encoded PGP message +``` + +## API Reference + +### `buildPlaintext(mnemonic, bip39PassphraseUsed, recipientFingerprints?)` + +Creates a SeedPGP plaintext object. + +**Parameters:** + +- `mnemonic` (string): BIP39 mnemonic phrase (12/18/24 words) +- `bip39PassphraseUsed` (boolean): Whether a BIP39 passphrase was used +- `recipientFingerprints` (string[]): Optional array of recipient key fingerprints + +**Returns:** `SeedPgpPlaintext` object + +### `encryptToSeedPgp(params)` + +Encrypts a plaintext object to SeedPGP format. + +**Parameters:** + +```typescript +{ + plaintext: SeedPgpPlaintext; + publicKeyArmored?: string; // PGP public key (PKESK) + messagePassword?: string; // Symmetric password (SKESK) +} +``` + +**Returns:** + +```typescript +{ + framed: string; // SEEDPGP1 frame + pgpBytes: Uint8Array; // Raw PGP message + recipientFingerprint?: string; // Key fingerprint +} +``` + +### `decryptSeedPgp(params)` + +Decrypts a SeedPGP frame. + +**Parameters:** + +```typescript +{ + frameText: string; // SEEDPGP1 frame + privateKeyArmored?: string; // PGP private key + privateKeyPassphrase?: string; // Key unlock password + messagePassword?: string; // SKESK password +} +``` + +**Returns:** `SeedPgpPlaintext` object + +## Testing + +```bash +# Run all tests +bun test + +# Run with verbose output +bun test --verbose + +# Watch mode (auto-rerun on changes) +bun test --watch +``` + +### Test Coverage + +- โœ… 15 comprehensive tests +- โœ… 8 official Trezor BIP39 test vectors +- โœ… Edge cases (wrong key, wrong passphrase) +- โœ… Frame format validation +- โœ… CRC16 integrity checking + +## Security Considerations + +### โœ… Best Practices + +- Uses **AES-256** for symmetric encryption +- **cv25519** provides ~128-bit security level +- **CRC16** detects QR scan errors (not cryptographic) +- Key fingerprint validation prevents wrong-key usage + +### โš ๏ธ Important Notes + +- **Never share your private key or encrypted QR codes publicly** +- Store backup QR codes in secure physical locations (safe, safety deposit box) +- Use a strong PGP key passphrase (20+ characters) +- Test decryption immediately after generating backups +- Consider password-only (SKESK) encryption as additional fallback + +## Project Structure + +``` +seedpgp-web/ +โ”œโ”€โ”€ src/ +โ”‚ โ”œโ”€โ”€ lib/ +โ”‚ โ”‚ โ”œโ”€โ”€ seedpgp.ts # Core encryption/decryption +โ”‚ โ”‚ โ”œโ”€โ”€ seedpgp.test.ts # Test vectors +โ”‚ โ”‚ โ”œโ”€โ”€ base45.ts # Base45 codec +โ”‚ โ”‚ โ”œโ”€โ”€ crc16.ts # CRC16-CCITT-FALSE +โ”‚ โ”‚ โ””โ”€โ”€ types.ts # TypeScript definitions +โ”‚ โ””โ”€โ”€ App.tsx # React UI +โ”œโ”€โ”€ package.json +โ””โ”€โ”€ README.md +``` + +## Tech Stack + +- **Runtime**: [Bun](https://bun.sh) v1.3.6+ +- **Language**: TypeScript +- **Crypto**: [OpenPGP.js](https://openpgpjs.org) v6.3.0 +- **Framework**: React + Vite +- **Testing**: Bun test runner + +## Roadmap + +- [ ] QR code generation UI +- [ ] Multi-frame support for larger payloads +- [ ] Hardware wallet integration +- [ ] Mobile scanning app +- [ ] Shamir Secret Sharing support + +## License + +MIT License - see LICENSE file for details + +## Author + +**kccleoc** - [GitHub](https://github.com/kccleoc) + +## Version History + +### v1.1.0 (2026-01-28) + +- Initial public release +- Full BIP39 mnemonic support +- Trezor test vector validation +- Production-ready implementation + +--- + +โš ๏ธ **Disclaimer**: This software is provided as-is. Always test thoroughly before trusting with real funds. The author is not responsible for lost funds due to software bugs or user error. -export default defineConfig([ - globalIgnores(['dist']), - { - files: ['**/*.{ts,tsx}'], - extends: [ - // Other configs... - // Enable lint rules for React - reactX.configs['recommended-typescript'], - // Enable lint rules for React DOM - reactDom.configs.recommended, - ], - languageOptions: { - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - // other options... - }, - }, -]) ```