Code Duplication    Length = 182-183 lines in 2 locations

src/index.js 1 location

@@ 1-183 (lines=183) @@
1
'use strict'
2
let BigInteger = require('bigi')
3
let ALPHABET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'
4
5
// pre-compute lookup table
6
let SEPARATOR = ':'
7
let CSLEN = 8
8
let ALPHABET_MAP = {}
9
for (let z = 0; z < ALPHABET.length; z++) {
10
    let x = ALPHABET.charAt(z)
11
    if (ALPHABET_MAP[x] !== undefined) {
12
        throw new TypeError(x + ' is ambiguous')
13
    }
14
    ALPHABET_MAP[x] = z
15
}
16
17
function polymodStep (pre) {
18
    let b = pre.shiftRight(35)
19
    let mask = BigInteger.fromHex('07ffffffff')
20
21
    let v = pre.and(mask).shiftLeft(new BigInteger('5'))
22
23
    if (b.and(new BigInteger('1')).intValue() > 0) {
24
        v = v.xor(BigInteger.fromHex('98f2bc8e61'))
25
    }
26
    if (b.and(new BigInteger('2')).intValue()) {
27
        v = v.xor(BigInteger.fromHex('79b76d99e2'))
28
    }
29
    if (b.and(new BigInteger('4')).intValue()) {
30
        v = v.xor(BigInteger.fromHex('f33e5fb3c4'))
31
    }
32
    if (b.and(new BigInteger('8')).intValue()) {
33
        v = v.xor(BigInteger.fromHex('ae2eabe2a8'))
34
    }
35
    if (b.and(new BigInteger('16')).intValue()) {
36
        v = v.xor(BigInteger.fromHex('1e4f43e470'))
37
    }
38
39
    return v
40
}
41
42
function prefixChk (prefix) {
43
    let chk = new BigInteger('1')
44
    for (let i = 0; i < prefix.length; ++i) {
45
        let c = prefix.charCodeAt(i)
46
47
        let mixwith = new BigInteger('' + (c & 0x1f))
48
        chk = polymodStep(chk).xor(mixwith)
49
    }
50
51
    chk = polymodStep(chk)
52
    return chk
53
}
54
55
function encode (prefix, words) {
56
    // too long?
57
    if ((prefix.length + CSLEN + 1 + words.length) > 90) {
58
        throw new TypeError('Exceeds Base32 maximum length')
59
    }
60
61
    prefix = prefix.toLowerCase()
62
63
    // determine chk mod
64
    let chk = prefixChk(prefix)
65
    let result = prefix + SEPARATOR
66
    for (let i = 0; i < words.length; ++i) {
67
        let x = words[i]
68
        if ((x >>> 5) !== 0) {
69
            throw new Error('Non 5-bit word')
70
        }
71
72
        chk = polymodStep(chk).xor(new BigInteger('' + x))
73
        result += ALPHABET.charAt(x)
74
    }
75
76
    for (let i = 0; i < CSLEN; ++i) {
77
        chk = polymodStep(chk)
78
    }
79
    chk = chk.xor(new BigInteger('1'))
80
    for (let i = 0; i < CSLEN; ++i) {
81
        let pos = 5 * (CSLEN - 1 - i)
82
        let v2 = chk.shiftRight(new BigInteger('' + pos)).and(BigInteger.fromHex('1f'))
83
        result += ALPHABET.charAt(v2.toString(10))
84
    }
85
86
    return result
87
}
88
89
function decode (str) {
90
    if (str.length < 8) {
91
        throw new TypeError(str + ' too short')
92
    }
93
    if (str.length > 90) {
94
        throw new TypeError(str + ' too long')
95
    }
96
97
    // don't allow mixed case
98
    let lowered = str.toLowerCase()
99
    let uppered = str.toUpperCase()
100
    if (str !== lowered && str !== uppered) {
101
        throw new Error('Mixed-case string ' + str)
102
    }
103
104
    str = lowered
105
106
    let split = str.lastIndexOf(SEPARATOR)
107
    if (split === -1) {
108
        throw new Error('No separator character for ' + str)
109
    }
110
111
    if (split === 0) {
112
        throw new Error('Missing prefix for ' + str)
113
    }
114
115
    let prefix = str.slice(0, split)
116
    let wordChars = str.slice(split + 1)
117
    if (wordChars.length < 6) {
118
        throw new Error('Data too short')
119
    }
120
121
    let chk = prefixChk(prefix)
122
    let words = []
123
    for (let i = 0; i < wordChars.length; ++i) {
124
        let c = wordChars.charAt(i)
125
        let v = ALPHABET_MAP[c]
126
        if (v === undefined) {
127
            throw new Error('Unknown character ' + c)
128
        }
129
130
        chk = polymodStep(chk).xor(new BigInteger('' + v))
131
        // not in the checksum?
132
        if (i + CSLEN >= wordChars.length) {
133
            continue
134
        }
135
        words.push(v)
136
    }
137
138
    if (chk.toString(10) !== '1') {
139
        throw new Error('Invalid checksum for ' + str)
140
    }
141
142
    return { prefix, words }
143
}
144
145
function convert (data, inBits, outBits, pad) {
146
    let value = 0
147
    let bits = 0
148
    let maxV = (1 << outBits) - 1
149
150
    let result = []
151
    for (let i = 0; i < data.length; ++i) {
152
        value = (value << inBits) | data[i]
153
        bits += inBits
154
155
        while (bits >= outBits) {
156
            bits -= outBits
157
            result.push((value >>> bits) & maxV)
158
        }
159
    }
160
161
    if (pad) {
162
        if (bits > 0) {
163
            result.push((value << (outBits - bits)) & maxV)
164
        }
165
    } else {
166
        if (bits >= inBits) {
167
            throw new Error('Excess padding')
168
        }
169
        if ((value << (outBits - bits)) & maxV) {
170
            throw new Error('Non-zero padding')
171
        }
172
    }
173
174
    return result
175
}
176
177
function toWords (bytes) {
178
    return convert(bytes, 8, 5, true)
179
}
180
181
function fromWords (words) {
182
    return convert(words, 5, 8, false)
183
}
184
185
module.exports = { decode, encode, toWords, fromWords }
186

lib/index.js 1 location

@@ 1-182 (lines=182) @@
1
'use strict';
2
3
var BigInteger = require('bigi');
4
var ALPHABET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
5
6
// pre-compute lookup table
7
var SEPARATOR = ':';
8
var CSLEN = 8;
9
var ALPHABET_MAP = {};
10
for (var z = 0; z < ALPHABET.length; z++) {
11
    var x = ALPHABET.charAt(z);
12
    if (ALPHABET_MAP[x] !== undefined) {
13
        throw new TypeError(x + ' is ambiguous');
14
    }
15
    ALPHABET_MAP[x] = z;
16
}
17
18
function polymodStep(pre) {
19
    var b = pre.shiftRight(35);
20
    var mask = BigInteger.fromHex('07ffffffff');
21
22
    var v = pre.and(mask).shiftLeft(new BigInteger('5'));
23
24
    if (b.and(new BigInteger('1')).intValue() > 0) {
25
        v = v.xor(BigInteger.fromHex('98f2bc8e61'));
26
    }
27
    if (b.and(new BigInteger('2')).intValue()) {
28
        v = v.xor(BigInteger.fromHex('79b76d99e2'));
29
    }
30
    if (b.and(new BigInteger('4')).intValue()) {
31
        v = v.xor(BigInteger.fromHex('f33e5fb3c4'));
32
    }
33
    if (b.and(new BigInteger('8')).intValue()) {
34
        v = v.xor(BigInteger.fromHex('ae2eabe2a8'));
35
    }
36
    if (b.and(new BigInteger('16')).intValue()) {
37
        v = v.xor(BigInteger.fromHex('1e4f43e470'));
38
    }
39
40
    return v;
41
}
42
43
function prefixChk(prefix) {
44
    var chk = new BigInteger('1');
45
    for (var i = 0; i < prefix.length; ++i) {
46
        var c = prefix.charCodeAt(i);
47
48
        var mixwith = new BigInteger('' + (c & 0x1f));
49
        chk = polymodStep(chk).xor(mixwith);
50
    }
51
52
    chk = polymodStep(chk);
53
    return chk;
54
}
55
56
function encode(prefix, words) {
57
    // too long?
58
    if (prefix.length + CSLEN + 1 + words.length > 90) {
59
        throw new TypeError('Exceeds Base32 maximum length');
60
    }
61
62
    prefix = prefix.toLowerCase();
63
64
    // determine chk mod
65
    var chk = prefixChk(prefix);
66
    var result = prefix + SEPARATOR;
67
    for (var i = 0; i < words.length; ++i) {
68
        var _x = words[i];
69
        if (_x >>> 5 !== 0) {
70
            throw new Error('Non 5-bit word');
71
        }
72
73
        chk = polymodStep(chk).xor(new BigInteger('' + _x));
74
        result += ALPHABET.charAt(_x);
75
    }
76
77
    for (var _i = 0; _i < CSLEN; ++_i) {
78
        chk = polymodStep(chk);
79
    }
80
    chk = chk.xor(new BigInteger('1'));
81
    for (var _i2 = 0; _i2 < CSLEN; ++_i2) {
82
        var pos = 5 * (CSLEN - 1 - _i2);
83
        var v2 = chk.shiftRight(new BigInteger('' + pos)).and(BigInteger.fromHex('1f'));
84
        result += ALPHABET.charAt(v2.toString(10));
85
    }
86
87
    return result;
88
}
89
90
function decode(str) {
91
    if (str.length < 8) {
92
        throw new TypeError(str + ' too short');
93
    }
94
    if (str.length > 90) {
95
        throw new TypeError(str + ' too long');
96
    }
97
98
    // don't allow mixed case
99
    var lowered = str.toLowerCase();
100
    var uppered = str.toUpperCase();
101
    if (str !== lowered && str !== uppered) {
102
        throw new Error('Mixed-case string ' + str);
103
    }
104
105
    str = lowered;
106
107
    var split = str.lastIndexOf(SEPARATOR);
108
    if (split === -1) {
109
        throw new Error('No separator character for ' + str);
110
    }
111
112
    if (split === 0) {
113
        throw new Error('Missing prefix for ' + str);
114
    }
115
116
    var prefix = str.slice(0, split);
117
    var wordChars = str.slice(split + 1);
118
    if (wordChars.length < 6) {
119
        throw new Error('Data too short');
120
    }
121
122
    var chk = prefixChk(prefix);
123
    var words = [];
124
    for (var i = 0; i < wordChars.length; ++i) {
125
        var c = wordChars.charAt(i);
126
        var v = ALPHABET_MAP[c];
127
        if (v === undefined) {
128
            throw new Error('Unknown character ' + c);
129
        }
130
131
        chk = polymodStep(chk).xor(new BigInteger('' + v));
132
        // not in the checksum?
133
        if (i + CSLEN >= wordChars.length) {
134
            continue;
135
        }
136
        words.push(v);
137
    }
138
139
    if (chk.toString(10) !== '1') {
140
        throw new Error('Invalid checksum for ' + str);
141
    }
142
143
    return { prefix: prefix, words: words };
144
}
145
146
function convert(data, inBits, outBits, pad) {
147
    var value = 0;
148
    var bits = 0;
149
    var maxV = (1 << outBits) - 1;
150
151
    var result = [];
152
    for (var i = 0; i < data.length; ++i) {
153
        value = value << inBits | data[i];
154
        bits += inBits;
155
156
        while (bits >= outBits) {
157
            bits -= outBits;
158
            result.push(value >>> bits & maxV);
159
        }
160
    }
161
162
    if (pad) {
163
        if (bits > 0) {
164
            result.push(value << outBits - bits & maxV);
165
        }
166
    } else {
167
        if (bits >= inBits) {
168
            throw new Error('Excess padding');
169
        }
170
        if (value << outBits - bits & maxV) {
171
            throw new Error('Non-zero padding');
172
        }
173
    }
174
175
    return result;
176
}
177
178
function toWords(bytes) {
179
    return convert(bytes, 8, 5, true);
180
}
181
182
function fromWords(words) {
183
    return convert(words, 5, 8, false);
184
}
185