UNPKG

j-bitcoin

Version:

Comprehensive JavaScript/TypeScript Bitcoin (BTC) wallet library with custodial and non-custodial support, hierarchical deterministic keys, threshold signatures, and advanced cryptographic features

400 lines (294 loc) โ€ข 12.7 kB
<p align="center"> <h1 align="center">๐Ÿ” J-Bitcoin</h1> <p align="center"> <strong>The Modern JavaScript Bitcoin Library</strong> </p> <p align="center"> HD Wallets โ€ข Threshold Signatures (TSS) โ€ข Schnorr/ECDSA โ€ข Taproot โ€ข Zero Dependencies* </p> </p> <p align="center"> <a href="https://www.npmjs.com/package/j-bitcoin"><img src="https://img.shields.io/npm/v/j-bitcoin.svg?style=flat-square&color=blue" alt="npm version"></a> <a href="https://www.npmjs.com/package/j-bitcoin"><img src="https://img.shields.io/npm/dw/j-bitcoin.svg?style=flat-square&color=green" alt="npm downloads"></a> <a href="https://github.com/yfbsei/J-Bitcoin"><img src="https://img.shields.io/github/stars/yfbsei/J-Bitcoin?style=flat-square" alt="GitHub stars"></a> <a href="https://opensource.org/licenses/ISC"><img src="https://img.shields.io/badge/License-ISC-blue.svg?style=flat-square" alt="License"></a> <a href="https://nodejs.org/"><img src="https://img.shields.io/badge/Node.js-16%2B-339933?style=flat-square&logo=node.js&logoColor=white" alt="Node.js"></a> <a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-Ready-3178C6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript"></a> </p> <p align="center"> <a href="#-quick-start">Quick Start</a> โ€ข <a href="#-features">Features</a> โ€ข <a href="#-api-reference">API</a> โ€ข <a href="https://github.com/yfbsei/J-Bitcoin/issues">Issues</a> </p> --- ## Why J-Bitcoin? | | J-Bitcoin | Others | |---|:---:|:---:| | **HD Wallets** (BIP32/39/44/49/84/86) | โœ… | โœ… | | **Threshold Signatures (TSS)** | โœ… | โŒ | | **Taproot (P2TR)** | โœ… | Some | | **Schnorr Signatures (BIP340)** | โœ… | Some | | **BIP322 Message Signing** | โœ… | โŒ | | **TypeScript Support** | โœ… | โœ… | | **Zero Native Dependencies*** | โœ… | โŒ | | **Testnet Verified** | โœ… | ? | <sub>*Only uses `@noble/curves` for cryptographic primitives</sub> --- ## โšก Quick Start ```bash npm install j-bitcoin ``` ### Create HD Wallet in 3 Lines ```javascript import { CustodialWallet } from 'j-bitcoin'; const { wallet, mnemonic } = CustodialWallet.createNew('main', 128); const address = wallet.getReceivingAddress(0, 0, 'segwit'); console.log('Backup:', mnemonic); console.log('Address:', address.address); // bc1q... ``` ### Threshold Signatures (2-of-3 TSS) ```javascript import { NonCustodialWallet } from 'j-bitcoin'; // No single point of failure - requires 3 parties to sign const { wallet, shares } = NonCustodialWallet.createNew('main', 3, 1); const signature = wallet.sign(messageHash); // Distributed signing ``` --- ## ๐Ÿš€ Features | Category | Features | |----------|----------| | **Wallets** | Custodial HD wallets, Non-custodial threshold wallets (TSS) | | **Standards** | BIP32, BIP39, BIP44, BIP49, BIP84, BIP86, BIP173, BIP322, BIP340, BIP350 | | **Addresses** | Legacy P2PKH (1...), P2SH-P2WPKH (3...), Native SegWit (bc1q...), Taproot (bc1p...) | | **Signatures** | ECDSA, Schnorr (BIP340), Threshold signatures (TSS), BIP322 message signing | | **Networks** | Bitcoin Mainnet, Testnet | --- ## ๐Ÿ“– Examples <details> <summary><strong>๐Ÿ”‘ Custodial HD Wallet (Full Example)</strong></summary> ```javascript import { CustodialWallet } from 'j-bitcoin'; // Generate new wallet (12-word mnemonic by default, 256 for 24-word) const { wallet, mnemonic } = CustodialWallet.createNew('main', 128); console.log('Backup mnemonic:', mnemonic); // Derive addresses (account, index, type) const legacy = wallet.getReceivingAddress(0, 0, 'legacy'); // 1... const wrapped = wallet.getReceivingAddress(0, 0, 'wrapped-segwit'); // 3... const segwit = wallet.getReceivingAddress(0, 0, 'segwit'); // bc1q... const taproot = wallet.getReceivingAddress(0, 0, 'taproot'); // bc1p... console.log('Legacy:', legacy.address); console.log('SegWit:', segwit.address); console.log('Taproot:', taproot.address); // Get change address const change = wallet.getChangeAddress(0, 0, 'segwit'); // Batch generate addresses const addresses = wallet.getAddresses(0, 'segwit', 20); // Restore from mnemonic const restored = CustodialWallet.fromMnemonic('main', mnemonic); // Export/import WIF const wif = wallet.exportWIF(0, 0, 0, 'segwit'); const wifWallet = CustodialWallet.fromWIF(wif); ``` </details> <details> <summary><strong>๐Ÿ” Non-Custodial Threshold Wallet (TSS)</strong></summary> ```javascript import { NonCustodialWallet } from 'j-bitcoin'; // Create TSS-only wallet (3 participants, threshold degree t=1) // Signing requires 2t+1 = 3 participants const { wallet, shares, config } = NonCustodialWallet.createNew('main', 3, 1); console.log('TSS config:', config); // Create HD + TSS wallet (combined mode) const { wallet: hdWallet, mnemonic, shares: hdShares } = NonCustodialWallet.createNewHD('main', 3, 1); // Get TSS aggregate public key address const tssAddress = wallet.getAddress('segwit'); // Get HD-derived addresses (same API as CustodialWallet) const segwitAddr = hdWallet.getReceivingAddress(0, 0, 'segwit'); // Sign message hash with TSS const messageHash = Buffer.alloc(32, 'test'); const signature = wallet.sign(messageHash); const isValid = wallet.verify(messageHash, signature); // Sign with HD-derived key const hdSig = hdWallet.signMessageHD('Hello Bitcoin!', 0, 0, 'segwit'); ``` </details> <details> <summary><strong>๐Ÿ“ BIP39 Mnemonic Operations</strong></summary> ```javascript import { BIP39 } from 'j-bitcoin'; // Generate 12-word mnemonic (128-bit) const { mnemonic } = BIP39.generateMnemonic(128); // Generate 24-word mnemonic (256-bit) const { mnemonic: mnemonic24 } = BIP39.generateMnemonic(256); // Validate mnemonic const isValid = BIP39.validateChecksum(mnemonic); // Derive seed (with optional passphrase) const seed = BIP39.deriveSeed(mnemonic, 'optional-passphrase'); ``` </details> <details> <summary><strong>โœ๏ธ Schnorr & ECDSA Signatures</strong></summary> ```javascript import { Schnorr, ECDSA } from 'j-bitcoin'; const privateKey = Buffer.alloc(32, 'key'); const messageHash = Buffer.alloc(32, 'msg'); // Schnorr (BIP340) const schnorr = new Schnorr(); const schnorrSig = await schnorr.sign(privateKey, messageHash); const schnorrPubKey = schnorr.getPublicKey(privateKey); const isValidSchnorr = await schnorr.verify(schnorrSig.signature, messageHash, schnorrPubKey); // ECDSA const ecdsaSig = ECDSA.sign(privateKey, messageHash); const ecdsaPubKey = ECDSA.getPublicKey(privateKey); const isValidEcdsa = ECDSA.verify(ecdsaSig, messageHash, ecdsaPubKey); ``` </details> <details> <summary><strong>๐Ÿ—๏ธ Transaction Building</strong></summary> ```javascript import { CustodialWallet } from 'j-bitcoin'; const wallet = CustodialWallet.fromMnemonic('main', mnemonic); // Create transaction builder const builder = wallet.createTransaction(); // Add inputs and outputs builder.addInput(txid, vout, sequence); builder.addOutput(address, amount); builder.setFeeRate(10); // sat/vB // Sign with wallet keys await wallet.signTransaction(builder, [ { account: 0, change: 0, index: 0, type: 'segwit' } ]); // Get raw transaction hex const rawTx = builder.build().toHex(); ``` </details> <details> <summary><strong>๐Ÿ“ Bech32 Address Encoding</strong></summary> ```javascript import { BECH32 } from 'j-bitcoin'; // Encode public key to SegWit address const address = BECH32.to_P2WPKH(publicKeyHex, 'main'); // Encode to Taproot address const taprootAddr = BECH32.to_P2TR(xOnlyPubKeyHex, 'main'); // Decode address const { program, version, type } = BECH32.decode(address); ``` </details> --- ## ๐Ÿ“š API Reference ### Wallet Classes | Class | Description | |-------|-------------| | `CustodialWallet` | Full HD wallet with BIP32/39/44/49/84/86 support | | `NonCustodialWallet` | Threshold (TSS) + HD hybrid wallet | ### Wallet Methods | Method | Description | |--------|-------------| | `createNew(network, strength)` | Create new wallet with mnemonic | | `fromMnemonic(network, mnemonic)` | Restore from BIP39 phrase | | `fromWIF(wif)` | Import from WIF private key | | `fromExtendedKey(network, xprv/xpub)` | Import from extended key | | `getReceivingAddress(account, index, type)` | Get external address | | `getChangeAddress(account, index, type)` | Get internal address | | `getAddresses(account, type, count)` | Batch generate addresses | | `signMessage(message, account, index, type)` | Sign message | | `createTransaction()` | Create transaction builder | | `signTransaction(builder, inputInfo)` | Sign transaction | | `exportWIF(account, change, index, type)` | Export key as WIF | ### Cryptographic Modules | Module | Description | |--------|-------------| | `BIP39` | Mnemonic generation (12-24 words), validation, seed derivation | | `ECDSA` | Standard Bitcoin signatures with recovery | | `Schnorr` | BIP340 Schnorr signatures | | `BECH32` | Bech32/Bech32m address encoding (BIP173/BIP350) | | `BIP322` | Generic message signing for all address types | | `b58encode` / `b58decode` | Base58Check encoding | --- ## ๐Ÿงช Testnet Verified All address types and signing algorithms have been tested on **Bitcoin Testnet4** with real transactions: | Address Type | Custodial | Non-Custodial (TSS) | |--------------|:---------:|:-------------------:| | Legacy (P2PKH) | โœ… | โœ… | | Wrapped SegWit (P2SH-P2WPKH) | โœ… | โœ… | | Native SegWit (P2WPKH) | โœ… | โœ… | | Taproot (P2TR) | โœ… | โœ… | --- ## ๐Ÿ“ Project Structure ``` src/ โ”œโ”€โ”€ wallet/ # Wallet implementations โ”‚ โ”œโ”€โ”€ custodial.js # HD wallet (BIP32/39/44/49/84/86) โ”‚ โ””โ”€โ”€ non-custodial.js # Threshold signature + HD wallet โ”œโ”€โ”€ bip/ # BIP standards โ”‚ โ”œโ”€โ”€ BIP173-BIP350.js # Bech32/Bech32m encoding โ”‚ โ”œโ”€โ”€ bip32/ # HD key derivation โ”‚ โ”œโ”€โ”€ bip39/ # Mnemonic generation โ”‚ โ””โ”€โ”€ bip49.js # P2SH-P2WPKH support โ”œโ”€โ”€ core/ โ”‚ โ”œโ”€โ”€ constants.js # Network/crypto constants โ”‚ โ”œโ”€โ”€ crypto/ โ”‚ โ”‚ โ”œโ”€โ”€ hash/ # RIPEMD160, HASH160 โ”‚ โ”‚ โ””โ”€โ”€ signatures/ # ECDSA, Schnorr, Threshold โ”‚ โ””โ”€โ”€ taproot/ # Taproot support โ”œโ”€โ”€ encoding/ โ”‚ โ”œโ”€โ”€ base58.js # Base58Check โ”‚ โ”œโ”€โ”€ base32.js # Bech32/Bech32m โ”‚ โ””โ”€โ”€ address/ # Address encode/decode โ”œโ”€โ”€ transaction/ โ”‚ โ”œโ”€โ”€ builder.js # Transaction construction โ”‚ โ”œโ”€โ”€ psbt.js # PSBT support โ”‚ โ”œโ”€โ”€ message-signing.js # BIP322 message signing โ”‚ โ””โ”€โ”€ script-builder.js # Script creation โ””โ”€โ”€ utils/ โ”œโ”€โ”€ validation.js # Input validation โ””โ”€โ”€ address-helpers.js # Address utilities ``` --- ## ๐Ÿ”’ Security > โš ๏ธ **Important**: This library handles private keys and cryptographic material. - **Never share** private keys, mnemonics, or threshold shares - **Test on testnet** before mainnet deployment - **Store securely** - use encrypted offline storage for mnemonics - **Validate inputs** - always validate addresses and signatures - **Clear sensitive data** - call `wallet.destroy()` when done --- ## ๐Ÿ› ๏ธ Development ```bash # Install dependencies npm install # Run tests npm test npm run test:coverage # Run wallet compliance tests node test/custodial-test.js node test/non-custodial-test.js # Run comprehensive feature tests (43 tests) node test/test-all-features.js # Run testnet testing (requires funding) node test/testnet-test.js # Lint and format npm run lint npm run format ``` --- ## ๐Ÿ“ฆ Dependencies - [@noble/curves](https://github.com/paulmillr/noble-curves) - Audited secp256k1 implementation - [bn.js](https://github.com/indutny/bn.js) - BigNum arithmetic --- ## ๐Ÿ“„ License ISC License - see [LICENSE](LICENSE) --- ## ๐Ÿ”— Links - [๐Ÿ“ฆ npm Package](https://www.npmjs.com/package/j-bitcoin) - [๐Ÿ’ป GitHub Repository](https://github.com/yfbsei/J-Bitcoin) - [๐Ÿ› Report Issues](https://github.com/yfbsei/J-Bitcoin/issues) --- <p align="center"> <strong>โญ Star this repo if you find it useful!</strong> </p> <p align="center"> Made with โค๏ธ for the Bitcoin community </p>