Members
(constant) CHARSET :string
Custom Base32 alphabet used in Bech32 and CashAddr address formats
This alphabet is carefully designed with several important properties:
- No mixed case: All lowercase to avoid confusion
- No ambiguous characters: Excludes 1, b, i, o which can be confused
- Error detection: Character positioning aids in polynomial checksum validation
- Human readable: Avoids characters that look similar in common fonts
The alphabet consists of: qpzry9x8gf2tvdw0s3jn54khce6mua7l
Character Index Mapping:
q=0, p=1, z=2, r=3, y=4, 9=5, x=6, 8=7, g=8, f=9, 2=10, t=11, v=12, d=13, w=14, 0=15,
s=16, 3=17, j=18, n=19, 5=20, 4=21, k=22, h=23, c=24, e=25, 6=26, m=27, u=28, a=29, 7=30, l=31
Type:
- string
- Source:
(constant) FEATURES :boolean
Library feature support matrix
Type:
- boolean
(constant) NETWORKS :Object
Supported cryptocurrency networks
Type:
- Object
(constant) table :string
Base58 alphabet used by Bitcoin (excludes confusing characters 0, O, I, l)
Type:
- string
- Default Value:
- 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
- Source:
Methods
address(versionByte, pubKey) → {string}
Generates a Bitcoin address from a public key using HASH160 and Base58Check encoding
This function implements the standard Bitcoin address generation algorithm:
Address Generation Process:
- Double Hash: SHA256(public_key) → RIPEMD160(hash) = HASH160
- Version Prefix: Prepend network version byte (0x00 mainnet, 0x6f testnet)
- Checksum: Calculate SHA256(SHA256(version + hash160))[0:4]
- Encoding: Base58Check encode (version + hash160 + checksum)
Address Types by Version Byte:
- 0x00 (mainnet): Addresses starting with "1"
- 0x6f (testnet): Addresses starting with "m" or "n"
- 0x05 (mainnet P2SH): Addresses starting with "3" (not implemented here)
The resulting address is a human-readable string that can receive Bitcoin payments and corresponds directly to the provided public key.
Parameters:
| Name | Type | Description |
|---|---|---|
versionByte |
number | Extended key version byte (determines address network) |
pubKey |
Buffer | Compressed 33-byte public key |
- Source:
Throws:
-
-
If public key is invalid format or length
- Type
- Error
-
-
-
If version byte is not recognized
- Type
- Error
-
Returns:
Base58Check-encoded Bitcoin address
- Type
- string
Examples
// Generate mainnet address
const pubKey = Buffer.from('0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2', 'hex');
const mainnetVersionByte = 0x0488b21e; // Extended public key version
const address = address(mainnetVersionByte, pubKey);
console.log(address);
// "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma" (mainnet address starting with "1")
// Generate testnet address
const testnetVersionByte = 0x043587cf; // Extended public key version (testnet)
const testAddress = address(testnetVersionByte, pubKey);
console.log(testAddress);
// "mhiH7BQkmD7LoosHhAAH5nE9YKGUcPz4hV" (testnet address starting with "m")
// Full workflow: private key → public key → address
import { getPublicKey } from '@noble/secp256k1';
const privateKey = Buffer.from('e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35', 'hex');
const publicKey = Buffer.from(getPublicKey(privateKey, true)); // Compressed
const bitcoinAddress = address(0x0488b21e, publicKey);
console.log('Private key:', privateKey.toString('hex'));
console.log('Public key:', publicKey.toString('hex'));
console.log('Address:', bitcoinAddress);
// Validate address generation
const knownPubKey = Buffer.from('0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', 'hex');
const knownAddress = address(0x0488b21e, knownPubKey);
console.log(knownAddress);
// Should produce: "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH"
b58encode(bufferKey) → {string}
Encodes binary data using Base58Check format with double SHA256 checksum
Base58Check encoding is Bitcoin's standard format for human-readable data that needs integrity protection. The process involves:
Encoding Algorithm:
- Input: Raw binary data (private keys, addresses, extended keys)
- Checksum: Calculate SHA256(SHA256(data)) and take first 4 bytes
- Concatenation: Append checksum to original data
- Base58 Encoding: Convert to Base58 using Bitcoin alphabet
Error Detection:
- Double SHA256 provides ~32 bits of error detection
- Probability of undetected error: ~1 in 4.3 billion
- Single character errors are always detected
- Most multi-character errors are detected
Character Set Benefits:
- Excludes visually similar characters (0, O, I, l)
- Case-sensitive for better error detection
- 58 characters provide good encoding efficiency
- Human-readable and suitable for copy/paste
Parameters:
| Name | Type | Description |
|---|---|---|
bufferKey |
Buffer | Binary data to encode (addresses, keys, etc.) |
- Source:
Throws:
-
-
If input is not a valid Buffer
- Type
- Error
-
-
-
If Base58 encoding fails (rare, usually indicates corruption)
- Type
- Error
-
Returns:
Base58Check encoded string with integrated checksum
- Type
- string
Examples
// Encode a Bitcoin private key (WIF format)
const privateKeyBytes = Buffer.concat([
Buffer.from([0x80]), // Mainnet private key version
Buffer.from('e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35', 'hex'),
Buffer.from([0x01]) // Compressed public key flag
]);
const wifPrivateKey = b58encode(privateKeyBytes);
console.log(wifPrivateKey);
// "L5HgWvFghocq1FmxSjKNaGhVN8f67p6xYg5pY7M8FE77HXwHtGGu"
// Encode a Bitcoin address (P2PKH format)
const hash160 = Buffer.from('76a04053bda0a88bda5177b86a15c3b29f559873', 'hex');
const addressBytes = Buffer.concat([
Buffer.from([0x00]), // Mainnet P2PKH version
hash160 // RIPEMD160(SHA256(publicKey))
]);
const bitcoinAddress = b58encode(addressBytes);
console.log(bitcoinAddress);
// "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH"
// Encode an extended public key (BIP32)
const extendedKeyData = Buffer.concat([
Buffer.from([0x04, 0x88, 0xb2, 0x1e]), // Mainnet xpub version
Buffer.from([0x00]), // Depth
Buffer.alloc(4, 0), // Parent fingerprint
Buffer.alloc(4, 0), // Child number
Buffer.from('873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508', 'hex'), // Chain code
Buffer.from('0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2', 'hex') // Public key
]);
const xpub = b58encode(extendedKeyData);
console.log(xpub);
// "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
// Demonstrate checksum protection
const testData = Buffer.from('Hello Bitcoin!', 'utf8');
const encoded = b58encode(testData);
console.log('Encoded:', encoded);
// Checksum validation would catch corruption:
// If you modify any character in the encoded string, decoding will fail
// due to checksum mismatch, protecting against typos and transmission errors
// Compare with raw Base58 (no checksum)
const rawData = Buffer.from('test data', 'utf8');
const base58Only = binary_to_base58(Uint8Array.from(rawData));
const base58Check = b58encode(rawData);
console.log('Raw Base58:', base58Only); // Shorter, no error detection
console.log('Base58Check:', base58Check); // Longer, with checksum protection
base32_encode(data) → {string}
Encodes 5-bit data values into Base32 string representation
This function converts an array of 5-bit values (0-31) into their corresponding Base32 characters using the Bitcoin/CashAddr alphabet. It's primarily used in the final step of Bech32 and CashAddr address generation after data has been converted from 8-bit to 5-bit representation.
Encoding Process:
- Input: Array of 5-bit integers (values 0-31)
- Mapping: Each value maps to corresponding character in CHARSET
- Output: Concatenated string of Base32 characters
Use Cases:
- Final encoding step for Bech32 SegWit addresses
- Payload encoding in Bitcoin Cash CashAddr format
- Checksum encoding for address validation
- Custom data encoding with Bitcoin-compatible alphabet
Parameters:
| Name | Type | Description |
|---|---|---|
data |
Uint8Array | Array.<number> | Array of 5-bit values (0-31) to encode |
- Source:
Throws:
-
-
If any input value is outside range 0-31
- Type
- Error
-
-
-
If input is not array-like or is empty
- Type
- Error
-
Returns:
Base32-encoded string using Bitcoin alphabet
- Type
- string
Examples
// Encode simple 5-bit values
const fiveBitData = new Uint8Array([0, 1, 2, 3, 4, 5]);
const encoded = base32_encode(fiveBitData);
console.log(encoded); // "qpzry9"
// Verify character mapping
console.log(encoded[0]); // "q" (index 0)
console.log(encoded[1]); // "p" (index 1)
console.log(encoded[2]); // "z" (index 2)
// Encode Bech32 address payload
// This would typically be the output of convertBits(hash, 8, 5)
const witnessProgram = new Uint8Array([
0, // Witness version
14, 8, 20, 6, 2, 8, 4, 21, 15, 12, 1, 1, 9, 25, 4, 11,
3, 23, 26, 10, 0, 31, 1, 15, 13, 26, 8, 21, 23, 4, 11, 2, 16
]);
const bech32Payload = base32_encode(witnessProgram);
console.log(bech32Payload);
// "qw508d6qejxtdg4y5r3zarvary0c5xw7k" (example P2WPKH payload)
// Encode CashAddr checksum
const checksumData = new Uint8Array([21, 15, 9, 14, 26, 20, 0, 15]);
const checksumString = base32_encode(checksumData);
console.log(checksumString); // "54n5063"
// Complete address generation workflow
function generateBech32Address(witnessVersion, witnessProgram) {
// Convert witness program from 8-bit to 5-bit
const converted = convertBits(witnessProgram, 8, 5);
// Prepend witness version
const data = new Uint8Array([witnessVersion, ...converted]);
// Calculate checksum (simplified)
const checksum = calculateBech32Checksum("bc", data);
// Encode payload and checksum
const payload = base32_encode(data);
const checksumStr = base32_encode(checksum);
return `bc1${payload}${checksumStr}`;
}
// Validation and round-trip testing
function validateEncoding() {
const testData = new Uint8Array(32); // 32 random 5-bit values
for (let i = 0; i < 32; i++) {
testData[i] = Math.floor(Math.random() * 32);
}
const encoded = base32_encode(testData);
console.log('Encoded length:', encoded.length); // Should equal testData.length
// Verify each character is in valid alphabet
for (const char of encoded) {
if (!CHARSET.includes(char)) {
throw new Error(`Invalid character in encoding: ${char}`);
}
}
console.log('✓ Encoding validation passed');
}
derive(path, keyopt, serialization_format) → {DerivationResult}
Derives child keys from parent keys using BIP32 hierarchical deterministic algorithm
This function implements the complete BIP32 child key derivation specification:
Derivation Process:
- Path Parsing: Converts BIP32 path notation (e.g., "m/0'/1/2") into numeric indices
- Hardened Detection: Identifies hardened derivation (') requiring private key access
- HMAC Computation: For each path component, computes HMAC-SHA512 with appropriate data
- Key Mathematics: Performs elliptic curve arithmetic to derive child keys
- Validation: Ensures derived keys are valid (non-zero, within curve order)
- Serialization: Updates metadata (depth, fingerprint, index) for child keys
Hardened vs Non-Hardened Derivation:
- Hardened (index ≥ 2³¹): Uses private key in HMAC, breaks public key derivation chain
- Non-Hardened (index < 2³¹): Uses public key in HMAC, allows public-only derivation
Security Implications:
- Hardened derivation prevents compromise of parent from child key + chain code
- Non-hardened allows watch-only wallets and public key derivation
- BIP44 recommends hardened derivation for account-level and above
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
path |
string | BIP32 derivation path (e.g., "m/44'/0'/0'/0/0") |
||
key |
string |
<optional> |
'' | Parent extended key in xprv/xpub or tprv/tpub format |
serialization_format |
Object | Parent key's serialization metadata |
- Source:
Throws:
-
-
"Public Key can't derive from hardend path" - Attempting hardened derivation from public key
- Type
- Error
-
-
-
If path format is invalid or contains non-numeric components
- Type
- Error
-
-
-
If parent key format is invalid or corrupted
- Type
- Error
-
-
-
If derived key is invalid (extremely rare: ~1 in 2^127)
- Type
- Error
-
Returns:
Tuple of [derived keys, child serialization format]
- Type
- DerivationResult
Examples
// Standard BIP44 Bitcoin account derivation
import { fromSeed } from './fromSeed.js';
const seed = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
const [masterKeys, masterFormat] = fromSeed(seed, "main");
// Derive account 0, change 0, address 0
const [accountKeys, accountFormat] = derive("m/44'/0'/0'", masterKeys.HDpri, masterFormat);
const [changeKeys, changeFormat] = derive("m/0", accountKeys.HDpri, accountFormat);
const [addressKeys, addressFormat] = derive("m/0", changeKeys.HDpri, changeFormat);
console.log("Final address key:", addressKeys.HDpub);
// Public key derivation (non-hardened only)
const [publicDerived, _] = derive("m/0/1/2", masterKeys.HDpub, masterFormat);
console.log("Public-derived key:", publicDerived.HDpub);
console.log("Private key:", publicDerived.HDpri); // null - no private key available
// Multi-level derivation with error handling
try {
// This will fail - can't derive hardened from public key
const [failed, _] = derive("m/0'", masterKeys.HDpub, masterFormat);
} catch (error) {
console.log(error.message); // "Public Key can't derive from hardend path"
}
// Complex derivation path
const complexPath = "m/49'/0'/0'/0/0"; // BIP49 P2SH-wrapped SegWit
const [segwitKeys, segwitFormat] = derive(complexPath, masterKeys.HDpri, masterFormat);
// Access derived key components
console.log("Depth:", segwitFormat.depth); // 5
console.log("Child index:", segwitFormat.childIndex); // 0
console.log("Parent fingerprint:", segwitFormat.parentFingerPrint.toString('hex'));
// Iterative derivation for address generation
let currentKeys = masterKeys;
let currentFormat = masterFormat;
const pathComponents = ["44'", "0'", "0'", "0"];
for (const component of pathComponents) {
[currentKeys, currentFormat] = derive(`m/${component}`, currentKeys.HDpri, currentFormat);
}
// Generate first 10 addresses
for (let i = 0; i < 10; i++) {
const [addrKeys, _] = derive(`m/${i}`, currentKeys.HDpri, currentFormat);
console.log(`Address ${i}:`, addrKeys.HDpub);
}
fromSeed(seed, netopt) → {MasterKeyResult}
Generates BIP32 master keys from a cryptographic seed
This function implements the BIP32 master key generation algorithm:
- HMAC-SHA512 Computation: Uses "Bitcoin seed" as HMAC key and input seed as data
- Key Material Split: Divides 512-bit result into 256-bit private key (IL) and 256-bit chain code (IR)
- Validation: Ensures IL is valid (non-zero and less than curve order)
- Public Key Derivation: Computes corresponding compressed public key
- Serialization: Creates extended key format with network-specific version bytes
The master keys serve as the root of the entire HD key tree, allowing deterministic derivation of billions of child keys while maintaining mathematical relationships between them for features like watch-only wallets and audit capabilities.
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
seed |
string | Hex-encoded cryptographic seed (typically 128-512 bits from BIP39) |
||
net |
string |
<optional> |
'main' | Network type: 'main' for Bitcoin mainnet, 'test' for testnet |
- Source:
Throws:
-
-
If seed results in invalid private key (extremely rare: ~1 in 2^127)
- Type
- Error
-
-
-
If seed is not valid hexadecimal
- Type
- Error
-
-
-
If network parameter is not recognized
- Type
- Error
-
Returns:
Tuple containing [HD key pair, serialization format]
- Type
- MasterKeyResult
Examples
// Generate master keys from BIP39 seed
const seed = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
const [hdKeys, format] = fromSeed(seed, "main");
console.log(hdKeys.HDpri);
// "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"
console.log(hdKeys.HDpub);
// "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
// Generate testnet master keys
const [testKeys, testFormat] = fromSeed(seed, "test");
console.log(testKeys.HDpri.substring(0, 4)); // "tprv" (testnet prefix)
console.log(testKeys.HDpub.substring(0, 4)); // "tpub" (testnet prefix)
// Use with BIP39 mnemonic-derived seed
import { bip39 } from '../BIP39/bip39.js';
const mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
const bip39Seed = bip39.mnemonic2seed(mnemonic, "passphrase");
const [masterKeys, _] = fromSeed(bip39Seed, "main");
// Access internal key material for advanced operations
const [_, format] = fromSeed(seed, "main");
console.log(format.privKey.key.toString('hex')); // Raw 32-byte private key
console.log(format.pubKey.key.toString('hex')); // Compressed 33-byte public key
console.log(format.chainCode.toString('hex')); // Chain code for child derivation
hdKey(keyType, params) → {string}
Encodes hierarchical deterministic keys according to BIP32 specification
This function creates extended keys (xprv/xpub, tprv/tpub) that contain not only the key material but also metadata necessary for hierarchical key derivation:
Extended Key Structure (78 bytes total):
- 4 bytes: Version (network and key type identifier)
- 1 byte: Depth (number of derivations from master)
- 4 bytes: Parent fingerprint (first 4 bytes of parent key hash)
- 4 bytes: Child index (derivation index used)
- 32 bytes: Chain code (for deriving child keys)
- 33 bytes: Key data (private key with 0x00 prefix OR compressed public key)
Network Prefixes:
- Mainnet: xprv/xpub (starts with "xprv9" or "xpub6")
- Testnet: tprv/tpub (starts with "tprv8" or "tpub8")
Parameters:
| Name | Type | Default | Description | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
keyType |
string | pri | Key type: 'pri' for private key, 'pub' for public key |
||||||||||||||||||||||||
params |
Object | BIP32 serialization parameters Properties
|
- Source:
Throws:
-
-
If keyType is neither 'pri' nor 'pub'
- Type
- Error
-
-
-
If required key information is missing for specified type
- Type
- Error
-
-
-
If serialization parameters are invalid or malformed
- Type
- Error
-
Returns:
Base58Check-encoded extended key
- Type
- string
Examples
// Create extended private key (xprv)
const masterFormat = {
versionByte: { privKey: 0x0488ade4, pubKey: 0x0488b21e },
depth: 0,
parentFingerPrint: Buffer.alloc(4, 0),
childIndex: 0,
chainCode: Buffer.from('873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508', 'hex'),
privKey: {
key: Buffer.from('e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35', 'hex'),
versionByteNum: 0x80
},
pubKey: {
key: Buffer.from('0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2', 'hex')
}
};
const xprv = hdKey('pri', masterFormat);
console.log(xprv);
// "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"
// Create extended public key (xpub)
const xpub = hdKey('pub', masterFormat);
console.log(xpub);
// "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
// Create testnet extended keys
const testnetFormat = { ...masterFormat };
testnetFormat.versionByte = { privKey: 0x04358394, pubKey: 0x043587cf };
const tprv = hdKey('pri', testnetFormat);
const tpub = hdKey('pub', testnetFormat);
console.log(tprv.substring(0, 4)); // "tprv"
console.log(tpub.substring(0, 4)); // "tpub"
// Child key with derivation metadata
const childFormat = {
versionByte: { privKey: 0x0488ade4, pubKey: 0x0488b21e },
depth: 3, // 3rd level derivation
parentFingerPrint: Buffer.from([0x5c, 0x1b, 0xd6, 0x48]), // Parent fingerprint
childIndex: 2147483647, // Hardened derivation (2^31 - 1)
chainCode: Buffer.from('47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141', 'hex'),
privKey: {
key: Buffer.from('cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca', 'hex'),
versionByteNum: 0x80
},
pubKey: {
key: Buffer.from('0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2', 'hex')
}
};
const childXprv = hdKey('pri', childFormat);
// This will produce an extended key reflecting the derivation path and depth
legacyAddress_decode(legacy_addropt) → {Uint8Array}
Decodes a legacy Bitcoin address to extract the HASH160 value
Legacy Bitcoin addresses use Base58Check encoding to represent the HASH160 of a public key or script. This function extracts the raw 20-byte hash from P2PKH (Pay to Public Key Hash) addresses, which is essential for address validation, conversion, and payment processing.
Legacy Address Structure:
- 1 byte: Version byte (0x00 mainnet P2PKH, 0x6f testnet P2PKH, 0x05 mainnet P2SH, etc.)
- 20 bytes: HASH160 value (RIPEMD160(SHA256(pubkey)) for P2PKH)
- 4 bytes: Checksum (first 4 bytes of double SHA256)
Address Types by Version:
- 0x00: Mainnet P2PKH (starts with "1")
- 0x05: Mainnet P2SH (starts with "3")
- 0x6f: Testnet P2PKH (starts with "m" or "n")
- 0xc4: Testnet P2SH (starts with "2")
The function focuses on P2PKH addresses but can decode any 25-byte legacy address format to extract the central hash value.
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
legacy_addr |
string |
<optional> |
"1EiBTNS9Dqhjhk7D78GMAjK9pZn5NXZf91" | Base58Check encoded legacy address |
- Source:
Throws:
-
-
If address format is invalid or corrupted
- Type
- Error
-
-
-
If Base58Check decoding fails (invalid checksum)
- Type
- Error
-
-
-
If address length is not 25 bytes after decoding
- Type
- Error
-
Returns:
Raw 20-byte HASH160 value
- Type
- Uint8Array
Examples
// Decode mainnet P2PKH address
const mainnetAddress = "1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2";
const hash160 = legacyAddress_decode(mainnetAddress);
console.log('Hash160 length:', hash160.length); // 20
console.log('Hash160 hex:', Array.from(hash160).map(b => b.toString(16).padStart(2, '0')).join(''));
// "76a04053bda0a88bda5177b86a15c3b29f559873"
// Decode testnet address
const testnetAddress = "mgRpP3zP1hmxyoeYJgfbcmN3c2Qsurw48D";
const testnetHash = legacyAddress_decode(testnetAddress);
console.log('Testnet hash160:', Buffer.from(testnetHash).toString('hex'));
// Verify address generation process
import { createHash } from 'crypto';
import rmd160 from './rmd160.js';
import { address } from './encodeKeys.js';
const originalAddress = "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma";
// Decode to get hash160
const decodedHash = legacyAddress_decode(originalAddress);
// Re-encode to verify
const versionByte = 0x0488b21e; // Mainnet extended key version
const regeneratedAddress = address(versionByte, Buffer.from(decodedHash));
console.log('Original: ', originalAddress);
console.log('Regenerated: ', regeneratedAddress);
console.log('Decoded hash: ', Buffer.from(decodedHash).toString('hex'));
// Extract hash for address conversion
import { CASH_ADDR } from '../altAddress/BCH/cash_addr.js';
const legacyAddr = "1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2";
const hash160 = legacyAddress_decode(legacyAddr);
// Use hash160 for CashAddr conversion
console.log('Legacy address:', legacyAddr);
console.log('Extracted hash:', Buffer.from(hash160).toString('hex'));
// Hash can now be used for format conversion
// Validate multiple address types
const addresses = [
{ addr: "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", type: "P2PKH mainnet" },
{ addr: "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy", type: "P2SH mainnet" },
{ addr: "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn", type: "P2PKH testnet" },
{ addr: "2MzQwSSnBHWHqSAqtTVQ6v47XtaisrJa1Vc", type: "P2SH testnet" }
];
addresses.forEach(({ addr, type }) => {
try {
const hash = legacyAddress_decode(addr);
console.log(`${type}: ${addr}`);
console.log(`Hash160: ${Buffer.from(hash).toString('hex')}\n`);
} catch (error) {
console.log(`Failed to decode ${addr}: ${error.message}\n`);
}
});
privateKey_decode(pri_keyopt) → {Uint8Array}
Decodes a WIF (Wallet Import Format) private key to raw bytes
WIF is the standard format for representing Bitcoin private keys in a human-readable way while maintaining security through Base58Check encoding. This function extracts the raw 32-byte private key material from the WIF-encoded string.
WIF Format Structure:
- 1 byte: Network version (0x80 mainnet, 0xef testnet)
- 32 bytes: Private key material
- 1 byte: Compression flag (0x01 if present, indicates compressed public key)
- 4 bytes: Checksum (first 4 bytes of double SHA256)
WIF Variants:
- Uncompressed WIF: 51 characters, no compression flag
- Compressed WIF: 52 characters, includes 0x01 compression flag
- Mainnet: Starts with '5' (uncompressed) or 'K'/'L' (compressed)
- Testnet: Starts with '9' (uncompressed) or 'c' (compressed)
The function automatically handles both compressed and uncompressed WIF formats, extracting only the 32-byte private key while discarding version bytes, compression flags, and checksums.
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
pri_key |
string |
<optional> |
"L1vHfV6GUbMJSvFaqjnButzwq5x4ThdFaotpUgsfScwMNKjdGVuS" | WIF-encoded private key |
- Source:
Throws:
-
-
If WIF format is invalid or corrupted
- Type
- Error
-
-
-
If Base58Check decoding fails (invalid checksum)
- Type
- Error
-
-
-
If private key length is incorrect after decoding
- Type
- Error
-
Returns:
Raw 32-byte private key material
- Type
- Uint8Array
Examples
// Decode compressed mainnet WIF private key
const compressedWIF = "L1vHfV6GUbMJSvFaqjnButzwq5x4ThdFaotpUgsfScwMNKjdGVuS";
const privateKeyBytes = privateKey_decode(compressedWIF);
console.log('Private key length:', privateKeyBytes.length); // 32
console.log('Private key hex:', Array.from(privateKeyBytes).map(b => b.toString(16).padStart(2, '0')).join(''));
// "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"
// Decode uncompressed mainnet WIF private key
const uncompressedWIF = "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ";
const rawKey = privateKey_decode(uncompressedWIF);
console.log('Decoded private key:', rawKey);
// Uint8Array of 32 bytes representing the private key
// Decode testnet WIF private key
const testnetWIF = "cTNsJGLYjVdwVULMBdLKNGKBJ3oVXAFGUk4mTDKhEqM4zbE6pEP7";
const testnetKey = privateKey_decode(testnetWIF);
console.log('Testnet private key length:', testnetKey.length); // 32
// Verify round-trip encoding/decoding
import { getPublicKey } from '@noble/secp256k1';
import { standardKey } from './encodeKeys.js';
const originalWIF = "L1vHfV6GUbMJSvFaqjnButzwq5x4ThdFaotpUgsfScwMNKjdGVuS";
// Decode to raw bytes
const decodedKey = privateKey_decode(originalWIF);
// Re-encode to WIF
const reEncodedWIF = standardKey({
key: Buffer.from(decodedKey),
versionByteNum: 0x80
}, null).pri;
console.log('Original WIF: ', originalWIF);
console.log('Re-encoded: ', reEncodedWIF);
console.log('Match: ', originalWIF === reEncodedWIF);
// Use with elliptic curve operations
import { signSync } from '@noble/secp256k1';
const wifKey = "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn";
const privateKeyBytes = privateKey_decode(wifKey);
const message = Buffer.from("Hello Bitcoin!", "utf8");
// Use decoded key for signing
const [signature, recovery] = signSync(message, privateKeyBytes, { recovered: true });
console.log('Signature created with decoded private key');
rmd160(buffer) → {Buffer}
Computes RIPEMD160 hash of input data
RIPEMD160 is a cryptographic hash function that produces a 160-bit (20-byte) digest. It's specifically used in Bitcoin for address generation as part of the HASH160 operation: RIPEMD160(SHA256(data)).
Algorithm Overview:
- Preprocessing: Pad message to multiple of 512 bits
- Processing: Process message in 512-bit (64-byte) chunks
- Rounds: Each chunk undergoes 5 rounds of 16 operations each
- Parallel Processing: Left and right sides processed simultaneously
- Combination: Results combined to produce final 160-bit hash
Security Properties:
- 160-bit output provides 2^80 collision resistance
- Designed to be resistant to differential and linear cryptanalysis
- More conservative design than SHA-1 with dual processing paths
- Suitable for applications requiring 160-bit hash values
Parameters:
| Name | Type | Description |
|---|---|---|
buffer |
Buffer | Uint8Array | ArrayBuffer | Input data to hash |
- Source:
Throws:
-
If input buffer is invalid or corrupted
- Type
- Error
Returns:
20-byte RIPEMD160 hash digest
- Type
- Buffer
Examples
// Hash a simple string
const message = Buffer.from('Hello Bitcoin!', 'utf8');
const hash = rmd160(message);
console.log(hash.toString('hex'));
// "b6a9c8c230722b7c748331a8b450f05566dc7d0f"
// Bitcoin address generation workflow
import { createHash } from 'crypto';
const publicKey = Buffer.from('0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2', 'hex');
// Step 1: SHA256 of public key
const sha256Hash = createHash('sha256').update(publicKey).digest();
// Step 2: RIPEMD160 of SHA256 result (this is HASH160)
const hash160 = rmd160(sha256Hash);
console.log('Public Key:', publicKey.toString('hex'));
console.log('SHA256:', sha256Hash.toString('hex'));
console.log('HASH160:', hash160.toString('hex'));
// Verify against known test vectors
const testVectors = [
{
input: '',
expected: '9c1185a5c5e9fc54612808977ee8f548b2258d31'
},
{
input: 'a',
expected: '0bdc9d2d256b3ee9daae347be6f4dc835a467ffe'
},
{
input: 'abc',
expected: '8eb208f7e05d987a9b044a8e98c6b087f15a0bfc'
}
];
testVectors.forEach(({ input, expected }) => {
const result = rmd160(Buffer.from(input, 'utf8'));
console.log(`Input: "${input}"`);
console.log(`Expected: ${expected}`);
console.log(`Got: ${result.toString('hex')}`);
console.log(`Match: ${result.toString('hex') === expected}\n`);
});
// Performance testing
function benchmarkRipemd160() {
const testData = Buffer.alloc(1024, 0xaa); // 1KB of test data
const iterations = 1000;
const startTime = Date.now();
for (let i = 0; i < iterations; i++) {
rmd160(testData);
}
const endTime = Date.now();
const avgTime = (endTime - startTime) / iterations;
console.log(`Average RIPEMD160 time: ${avgTime.toFixed(2)}ms per 1KB`);
}
// Handle different input types
const stringInput = Buffer.from('test message', 'utf8');
const arrayInput = new Uint8Array([0x01, 0x02, 0x03, 0x04]);
const bufferInput = Buffer.from([0x05, 0x06, 0x07, 0x08]);
console.log('String hash:', rmd160(stringInput).toString('hex'));
console.log('Array hash:', rmd160(arrayInput).toString('hex'));
console.log('Buffer hash:', rmd160(bufferInput).toString('hex'));
standardKey(privKey, pubKey) → {StandardKeyPair}
Encodes private and public keys in standard Bitcoin formats
This function creates standard key representations used throughout Bitcoin:
- WIF (Wallet Import Format): For private keys with network identification and compression flag
- Hex Encoding: For public keys in standard compressed format
WIF Format Structure:
- 1 byte: Network version (0x80 mainnet, 0xef testnet)
- 32 bytes: Private key
- 1 byte: Compression flag (0x01 for compressed public key)
- 4 bytes: Checksum (first 4 bytes of double SHA256)
The compression flag indicates that the corresponding public key should be stored in compressed format (33 bytes vs 65 bytes uncompressed).
Parameters:
| Name | Type | Description |
|---|---|---|
privKey |
PrivateKeyInfo | false | Private key info or false to skip private key encoding |
pubKey |
PublicKeyInfo | Public key information for hex encoding |
- Source:
Returns:
Object containing encoded private and public keys
- Type
- StandardKeyPair
Examples
// Encode both private and public keys
const privKeyInfo = {
key: Buffer.from('e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35', 'hex'),
versionByteNum: 0x80 // Mainnet
};
const pubKeyInfo = {
key: Buffer.from('0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2', 'hex')
};
const keyPair = standardKey(privKeyInfo, pubKeyInfo);
console.log(keyPair.pri);
// "L5HgWvFghocq1FmxSjKNaGhVN8f67p6xYg5pY7M8FE77HXwHtGGu"
console.log(keyPair.pub);
// "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"
// Encode only public key (watch-only wallet)
const publicOnly = standardKey(false, pubKeyInfo);
console.log(publicOnly.pri); // null
console.log(publicOnly.pub); // "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"
// Testnet private key encoding
const testnetPrivKey = {
key: Buffer.from('e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35', 'hex'),
versionByteNum: 0xef // Testnet
};
const testnetKeys = standardKey(testnetPrivKey, pubKeyInfo);
console.log(testnetKeys.pri);
// "cTNsJG5wZ3CZUKCy3vSHzXJHrR4eo2C3RKqR8YbdQQVQH4Tb6nHy" (testnet WIF)
Type Definitions
AddressInfo
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
address |
string | Bitcoin address string |
format |
string | Address format ('legacy', 'segwit', 'cashaddr') |
network |
string | Network type ('main', 'test') |
ChildKeyInfo
Information about a derived child key in the HD wallet tree
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
depth |
number | Derivation depth in the HD tree (0 = master, 1 = account, etc.) |
childIndex |
number | Index of this child key in its derivation level |
hdKey |
HDKeys | HD key pair for this child |
keypair |
KeyPair | Standard key pair for this child |
address |
string | Bitcoin address generated from this child key |
- Source:
Example
// Child key at m/44'/0'/0'/0/0
const childInfo = {
depth: 5,
childIndex: 0,
hdKey: { HDpri: "...", HDpub: "..." },
keypair: { pri: "...", pub: "..." },
address: "1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2"
};
DecodedAddress
Array containing [network prefix, hex hash]
Type:
- Array.<string>
- Source:
Example
["bitcoincash", "76a04053bda0a88bda5177b86a15c3b29f559873"]
DerivationResult
Array containing derived HD keys and updated serialization format
Type:
- Array
Properties:
| Name | Type | Description |
|---|---|---|
0 |
DerivedKeyPair | Derived key pair with HDpri and HDpub |
1 |
Object | Updated serialization format for further derivations |
- Source:
DerivedKeyPair
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
HDpri |
string | null | Extended private key (null if deriving from public key only) |
HDpub |
string | Extended public key |
- Source:
ECDSASignatureResult
Array containing signature bytes and recovery ID
Type:
- Array
Properties:
| Name | Type | Description |
|---|---|---|
0 |
Uint8Array | DER-encoded signature bytes |
1 |
number | Recovery ID (0-3) for public key recovery |
- Source:
ECDSASignatureResult
ECDSA signature result with recovery information
Type:
- Array
Properties:
| Name | Type | Description |
|---|---|---|
0 |
Uint8Array | DER-encoded signature bytes |
1 |
number | Recovery ID (0-3) for public key recovery |
- Source:
Example
const [signature, recoveryId] = wallet.sign("Hello Bitcoin!");
console.log(signature); // Uint8Array with signature bytes
console.log(recoveryId); // Number 0-3
HDKeyPair
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
HDpri |
string | Extended private key in xprv format (Base58Check encoded) |
HDpub |
string | Extended public key in xpub format (Base58Check encoded) |
- Source:
HDKeyPair
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
HDpri |
string | xprv-formatted hierarchical deterministic private key |
HDpub |
string | xpub-formatted hierarchical deterministic public key |
HDKeys
Hierarchical deterministic key pair following BIP32 specification
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
HDpri |
string | Extended private key in xprv/tprv format (Base58Check encoded) |
HDpub |
string | Extended public key in xpub/tpub format (Base58Check encoded) |
- Source:
Example
// Example HD key pair
const hdKeys = {
HDpri: "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
HDpub: "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
};
InterpolationPoints
Array of [x, y] coordinate pairs for polynomial interpolation
Type:
- Array.<Array.<number>>
Example
[[1, 123], [2, 456], [3, 789]]
KeyPair
Standard Bitcoin key pair for cryptographic operations
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
pri |
string | WIF-encoded private key (Wallet Import Format) |
pub |
string | Hex-encoded compressed public key (33 bytes) |
- Source:
Example
// Example key pair
const keyPair = {
pri: "L5HgWvFghocq1FmxSjKNaGhVN8f67p6xYg5pY7M8FE77HXwHtGGu",
pub: "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"
};
MasterKeyResult
Array containing the HD key pair and internal serialization format
Type:
- Array
Properties:
| Name | Type | Description |
|---|---|---|
0 |
HDKeyPair | HD key pair with HDpri and HDpub |
1 |
SerializationFormat | Internal serialization format |
- Source:
MnemonicResult
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
mnemonic |
string | 12-word mnemonic phrase |
seed |
string | Hex-encoded 64-byte seed derived from mnemonic |
- Source:
PrivateKeyInfo
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
key |
Buffer | 32-byte private key material |
versionByteNum |
number | Version byte for WIF encoding (0x80 mainnet, 0xef testnet) |
- Source:
PrivateKeyInfo
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
key |
Buffer | Raw 32-byte private key material |
versionByteNum |
number | WIF version byte (0x80 mainnet, 0xef testnet) |
- Source:
PublicKeyInfo
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
key |
Buffer | 33-byte compressed public key |
points |
Point | Elliptic curve point representation for cryptographic operations |
- Source:
PublicKeyInfo
Type:
- Object
Properties:
| Name | Type | Attributes | Description |
|---|---|---|---|
key |
Buffer | Compressed 33-byte public key |
|
points |
Point |
<optional> |
Optional elliptic curve point representation |
- Source:
SerializationFormat
Type:
- Object
Properties:
| Name | Type | Description | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
versionByte |
Object | Network-specific version bytes for key serialization Properties
|
|||||||||
depth |
number | Key depth in the derivation tree (0 for master) |
|||||||||
parentFingerPrint |
Buffer | 4-byte fingerprint of parent key (all zeros for master) |
|||||||||
childIndex |
number | Child key index (0 for master) |
|||||||||
chainCode |
Buffer | 32-byte chain code for HMAC operations |
|||||||||
privKey |
PrivateKeyInfo | Master private key information |
|||||||||
pubKey |
PublicKeyInfo | Master public key information |
- Source:
SharePoints
Array of [x, y] coordinate pairs for polynomial interpolation
Type:
- Array.<Array.<number>>
Example
[[1, share1], [2, share2], [3, share3]]
StandardKeyPair
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
pri |
string | null | WIF-encoded private key or null if not available |
pub |
string | Hex-encoded compressed public key |
- Source:
ThresholdSignatureResult
Type:
- Object
Properties:
| Name | Type | Description | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
sig |
Object | ECDSA signature object with r and s components Properties
|
|||||||||
serialized_sig |
string | Base64-encoded compact signature format |
|||||||||
msgHash |
Buffer | SHA256 hash of the signed message |
|||||||||
recovery_id |
number | Recovery ID for public key recovery (0-3) |
ThresholdSignatureResult
Complete threshold signature with metadata and recovery information
Type:
- Object
Properties:
| Name | Type | Description | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
sig |
Object | ECDSA signature object with r and s components Properties
|
|||||||||
serialized_sig |
string | Base64-encoded compact signature format (65 bytes) |
|||||||||
msgHash |
Buffer | SHA256 hash of the signed message (32 bytes) |
|||||||||
recovery_id |
number | Recovery ID for public key recovery (0-3) |
- Source:
Example
const signature = thresholdWallet.sign("Multi-party transaction");
console.log(signature.sig.r); // BigInt r value
console.log(signature.serialized_sig); // "base64-encoded-signature"
console.log(signature.recovery_id); // 0, 1, 2, or 3
VersionBytes
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
pubKey |
number | Version byte for extended public key (0x0488b21e mainnet, 0x043587cf testnet) |
privKey |
number | Version byte for extended private key (0x0488ade4 mainnet, 0x04358394 testnet) |
- Source:
WalletKeyPair
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
pri |
string | WIF-encoded private key |
pub |
string | Hex-encoded public key |