Passed
Push — master ( 7d8ce1...3a91ad )
by thomas
01:07
created

index.js ➔ createVersion   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 7
ccs 3
cts 3
cp 1
crap 4
rs 9.2
1
'use strict'
2
/** global: Buffer */
3
4 1
let base32 = require('./base32')
5
6 1
let P2SH = "scripthash";
7 1
let P2PKH = "pubkeyhash";
8
9 1
let hashBitMap = {};
10 1
hashBitMap[160] = 0;
11 1
hashBitMap[192] = 1;
12 1
hashBitMap[224] = 2;
13 1
hashBitMap[256] = 3;
14 1
hashBitMap[320] = 4;
15 1
hashBitMap[384] = 5;
16 1
hashBitMap[448] = 6;
17 1
hashBitMap[512] = 7;
18
19 1
let versionBitMap = {};
20 1
versionBitMap[P2PKH] = 0;
21 1
versionBitMap[P2SH] = 1;
22
23
function checkMap(mapObj, value) {
24 21
    let keys = Object.keys(mapObj);
25 21
    for (let i = 0; i < keys.length; i++) {
26 30
        if (mapObj[keys[i]] === value) {
27 20
            return keys[i];
28
        }
29
    }
30
31 1
    return null;
32
}
33
34
function createVersion(scriptType, hashLengthBits) {
35 9
    if ((scriptType === P2PKH || scriptType === P2SH) && hashLengthBits !== 160) {
36 1
        throw new Error("Invalid hash length for scriptType");
37
    }
38
39 8
    return (versionBitMap[scriptType] << 3) | hashBitMap[hashLengthBits];
40
}
41
42
function encodePayload(scriptType, hash) {
43 9
    let hashLength = hash.length
44 9
    let version = createVersion(scriptType, hashLength * 8)
45 8
    let payload = Buffer.allocUnsafe(1 + hash.length)
46 8
    payload.writeUInt8(version, 0)
47 8
    hash.copy(payload, 1)
48 8
    return payload
49
}
50
51
function decodeVersion (version) {
52 12
    let last = (version >>> 7);
53 12
    if (last & 1 || last > 0) {
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
54 1
        throw new Error("Invalid version, most significant bit is reserved");
55
    }
56
57 11
    let scriptType = checkMap(versionBitMap, (version >> 3) & 0x0f)
58 11
    if (scriptType === null) {
59 1
        throw new Error("Invalid script type");
60
    }
61
    // all possible values return
62 10
    let hashSize = parseInt(checkMap(hashBitMap, version & 0x07), 10);
63 10
    if ((scriptType === P2PKH || scriptType === P2SH) && hashSize !== 160) {
64 1
        throw new Error("Mismatch between script type and hash length");
65
    }
66
67 9
    return {scriptType, hashSize}
68
}
69
70
function encode (prefix, scriptType, hash) {
71 11
    if (!(hash instanceof Buffer)) {
72 1
        throw new Error("Hash should be passed as a Buffer")
73
    }
74
75 10
    if (!(scriptType in versionBitMap)) {
76 1
        throw new Error("Unsupported script type")
77
    }
78
79 9
    return base32.encode(
80
        prefix,
81
        base32.toWords(encodePayload(scriptType, hash))
82
    )
83
}
84
85
function decode(address) {
86 13
    let result = base32.decode(address)
87 13
    let data = base32.fromWords(result.words)
88 13
    if (data.length < 1) {
89 1
        throw new Error("Empty payload in address")
90
    }
91
92 12
    let versionInfo = decodeVersion(data[0])
93 9
    if (1 + (versionInfo.hashSize / 8) !== data.length) {
94 1
        throw new Error('Hash length does not match version')
95
    }
96
97 8
    return {
98
        version: versionInfo.scriptType,
99
        prefix: result.prefix,
100
        hash: Buffer.from(data.slice(1))
101
    }
102
}
103
104
module.exports = { decode: decode, encode: encode };
105