All files Wif.ts

100% Statements 17/17
90.91% Branches 10/11
100% Functions 3/3
100% Lines 16/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 851x 1x               1x             7x 14x   1x                                                 6x       6x     6x                           11x   11x 1x       10x     10x     10x     10x      
import { BitcoinError, BitcoinErrorCode, Network } from ".";
import { Base58Check } from "./Base58Check";
 
export type WifDecodeResult = {
    privateKey: Buffer;
    compressed: boolean;
    prefix: number;
};
 
export class Wif {
    /**
     * Finds the associated network for the given prefix
     * @param prefix single byte prefix
     * @returns
     */
    public static decodePrefix(prefix: number): Network {
        for (const network of Network.all) {
            if (network.wifPrefix === prefix) return network;
        }
        throw new BitcoinError(BitcoinErrorCode.UnknownWifPrefix, { prefix });
    }
 
    /**
     * Encodes a private key using the WIF format. Can encode with compressed
     * or uncompressed format and can be for testnet or mainnet.
     *
     * Mainnet prefix: 0x80
     * Testnet prefix: 0xef
     *
     * Algorithm for WIF is:
     * 1. Start with the prefix
     * 2. Encode the secret in 32-byte big-endian format
     * 3. If the SEC format used for the public key address was compressed add
     *    a suffix of 0x01
     * 4. Combine wthe prefix from #1, serialized secret from #2, and suffix from #3
     * 5. Do hash256 of the result from #4 and get the first 4 bytes
     * 6. Take the combination of #4 and #5 and encode it with Base58
     *
     * @param prefix a single byte prefix, usually 0x05 for mainnet or 0xef for testnet
     * @param privateKey a 32-byte private key as a big-endian buffer
     * @param compressed default of true
     */
    public static encode(prefix: number, privateKey: Buffer, compressed: boolean = true) {
        // 1. prefix
        const prefixBuf = Buffer.from([prefix]);
 
        // 2. encode as 32-byte big-endian number
        // 3. suffix
        const suffix = compressed ? Buffer.from([0x01]) : Buffer.alloc(0);
 
        // 4. combine 1, 2, and 3
        return Base58Check.encode(Buffer.concat([prefixBuf, privateKey, suffix]));
    }
 
    /**
     * To decode a WIF value, we must first decode the base58check
     * input. If this validates then we need to split the resulting
     * buffer of data into two or three parts.
     *
     * The first byte is the prefix
     * The next 32-bytes are the private key
     *
     * @param buf
     */
    public static decode(input: string): WifDecodeResult {
        const raw = Base58Check.decode(input);
 
        if (raw.length !== 33 && raw.length !== 34) {
            throw new BitcoinError(BitcoinErrorCode.InvalidWifEncoding, { input });
        }
 
        // prefix is the first byte
        const prefix = raw[0];
 
        // next 32-bytes are the private key
        const privateKey = raw.slice(1, 33);
 
        // check for compressed byte
        const compressed = raw.length === 34 && raw[33] === 0x01;
 
        // return our result object
        return { privateKey, compressed, prefix };
    }
}