UNPKG

6.91 kBJavaScriptView Raw
1/*!
2 * base32.js - base32 for bcoin
3 * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
4 * https://github.com/bcoin-org/bcoin
5 */
6
7'use strict';
8
9const assert = require('assert');
10const base32 = exports;
11
12/*
13 * Constants
14 */
15
16const CHARSET = 'abcdefghijklmnopqrstuvwxyz234567';
17const TABLE = [
18 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
19 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
23 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
24 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
25 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1
26];
27
28const CHARSET_HEX = '0123456789abcdefghijklmnopqrstuv';
29const TABLE_HEX = [
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
34 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
35 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1,
36 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
37 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1
38];
39
40const PADDING = [0, 6, 4, 3, 1];
41
42/**
43 * Encode a base32 string.
44 * @param {Buffer} data
45 * @param {Boolean} [pad=false]
46 * @returns {String}
47 */
48
49base32.encode = function encode(data, pad = false) {
50 return base32._encode(data, CHARSET, pad);
51};
52
53/**
54 * Encode a base32hex string.
55 * @param {Buffer} data
56 * @param {Boolean} [pad=false]
57 * @returns {String}
58 */
59
60base32.encodeHex = function encodeHex(data, pad = false) {
61 return base32._encode(data, CHARSET_HEX, pad);
62};
63
64/**
65 * Encode a base32 string.
66 * @private
67 * @param {Buffer} data
68 * @param {String} CHARSET
69 * @param {Boolean} [pad=false]
70 * @returns {String}
71 */
72
73base32._encode = function _encode(data, CHARSET, pad = false) {
74 assert(Buffer.isBuffer(data));
75 assert(typeof pad === 'boolean');
76
77 let str = '';
78 let mode = 0;
79 let left = 0;
80
81 for (let i = 0; i < data.length; i++) {
82 const ch = data[i];
83 switch (mode) {
84 case 0:
85 str += CHARSET[ch >>> 3];
86 left = (ch & 7) << 2;
87 mode = 1;
88 break;
89 case 1:
90 str += CHARSET[left | (ch >>> 6)];
91 str += CHARSET[(ch >>> 1) & 31];
92 left = (ch & 1) << 4;
93 mode = 2;
94 break;
95 case 2:
96 str += CHARSET[left | (ch >>> 4)];
97 left = (ch & 15) << 1;
98 mode = 3;
99 break;
100 case 3:
101 str += CHARSET[left | (ch >>> 7)];
102 str += CHARSET[(ch >>> 2) & 31];
103 left = (ch & 3) << 3;
104 mode = 4;
105 break;
106 case 4:
107 str += CHARSET[left | (ch >>> 5)];
108 str += CHARSET[ch & 31];
109 mode = 0;
110 break;
111 }
112 }
113
114 if (mode > 0) {
115 str += CHARSET[left];
116 if (pad) {
117 for (let i = 0; i < PADDING[mode]; i++)
118 str += '=';
119 }
120 }
121
122 return str;
123};
124
125/**
126 * Decode a base32 string.
127 * @param {String} str
128 * @param {Boolean} [unpad=false]
129 * @returns {Buffer}
130 */
131
132base32.decode = function decode(str, unpad = false) {
133 return base32._decode(str, TABLE, unpad);
134};
135
136/**
137 * Decode a base32hex string.
138 * @param {String} str
139 * @param {Boolean} [unpad=false]
140 * @returns {Buffer}
141 */
142
143base32.decodeHex = function decodeHex(str, unpad = false) {
144 return base32._decode(str, TABLE_HEX, unpad);
145};
146
147/**
148 * Decode a base32 string.
149 * @private
150 * @param {String} str
151 * @param {Object} TABLE
152 * @param {Boolean} [unpad=false]
153 * @returns {Buffer}
154 */
155
156base32._decode = function _decode(str, TABLE, unpad) {
157 assert(typeof str === 'string');
158 assert(typeof unpad === 'boolean');
159
160 const data = Buffer.allocUnsafe(str.length * 5 / 8 | 0);
161
162 let mode = 0;
163 let left = 0;
164 let j = 0;
165 let i = 0;
166
167 for (; i < str.length; i++) {
168 const ch = str.charCodeAt(i);
169 const v = (ch & 0xff80) ? -1 : TABLE[ch];
170
171 if (v === -1) {
172 if (unpad && mode > 0)
173 break;
174 throw new Error('Non-base32 character.');
175 }
176
177 switch (mode) {
178 case 0:
179 left = v;
180 mode = 1;
181 break;
182 case 1:
183 data[j++] = (left << 3) | (v >>> 2);
184 left = v & 3;
185 mode = 2;
186 break;
187 case 2:
188 left = left << 5 | v;
189 mode = 3;
190 break;
191 case 3:
192 data[j++] = (left << 1) | (v >>> 4);
193 left = v & 15;
194 mode = 4;
195 break;
196 case 4:
197 data[j++] = (left << 4) | (v >>> 1);
198 left = v & 1;
199 mode = 5;
200 break;
201 case 5:
202 left = left << 5 | v;
203 mode = 6;
204 break;
205 case 6:
206 data[j++] = (left << 2) | (v >>> 3);
207 left = v & 7;
208 mode = 7;
209 break;
210 case 7:
211 data[j++] = (left << 5) | v;
212 mode = 0;
213 break;
214 }
215 }
216
217 if (unpad) {
218 switch (mode) {
219 case 0:
220 break;
221 case 1:
222 case 3:
223 case 6:
224 throw new Error('Invalid base32 string.');
225 case 2:
226 if (left > 0)
227 throw new Error('Invalid padding.');
228
229 if (str.length !== i + 6)
230 throw new Error('Invalid padding.');
231
232 if (str.substring(i, i + 6) !== '======')
233 throw new Error('Invalid base32 character.');
234
235 break;
236 case 4:
237 if (left > 0)
238 throw new Error('Invalid padding.');
239
240 if (str.length !== i + 4)
241 throw new Error('Invalid padding.');
242
243 if (str.substring(i, i + 4) !== '====')
244 throw new Error('Invalid base32 character.');
245
246 break;
247 case 5:
248 if (left > 0)
249 throw new Error('Invalid padding.');
250
251 if (str.length !== i + 3)
252 throw new Error('Invalid padding.');
253
254 if (str.substring(i, i + 3) !== '===')
255 throw new Error('Invalid base32 character.');
256
257 break;
258 case 7:
259 if (left > 0)
260 throw new Error('Invalid padding.');
261
262 if (str.length !== i + 1)
263 throw new Error('Invalid padding.');
264
265 if (str[i] !== '=')
266 throw new Error('Invalid base32 character.');
267
268 break;
269 }
270 }
271
272 return data.slice(0, j);
273};
274
275/**
276 * Test a base32 string.
277 * @param {String} str
278 * @param {Boolean} [unpad=false]
279 * @returns {Buffer}
280 */
281
282base32.test = function test(str, unpad = false) {
283 try {
284 base32.decode(str, unpad);
285 return true;
286 } catch (e) {
287 return false;
288 }
289};
290
291/**
292 * Test a base32 hex string.
293 * @param {String} str
294 * @param {Boolean} [unpad=false]
295 * @returns {Buffer}
296 */
297
298base32.testHex = function testHex(str, unpad = false) {
299 try {
300 base32.decodeHex(str, unpad);
301 return true;
302 } catch (e) {
303 return false;
304 }
305};