Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
263 changes: 92 additions & 171 deletions lib/base32.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
'use strict';
"use strict";

var BigInteger = require('bigi');
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }

var ALPHABET = 'abcdefghjkmnprstuvwxyz0123456789'; // pre-compute lookup table
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

var SEPARATOR = ':';
var CSLEN = 8;
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

var JSBI = require('jsbi');

var ALPHABET = 'ABCDEFGHJKMNPRSTUVWXYZ0123456789';
var ALPHABET_MAP = {};

for (var z = 0; z < ALPHABET.length; z++) {
Expand All @@ -16,195 +19,113 @@ for (var z = 0; z < ALPHABET.length; z++) {
}

ALPHABET_MAP[x] = z;
}

function polymodStep(pre) {
var b = pre.shiftRight(35);
var mask = BigInteger.fromHex('07ffffffff');
var v = pre.and(mask).shiftLeft(new BigInteger('5'));

if (b.and(new BigInteger('1')).intValue() > 0) {
v = v.xor(BigInteger.fromHex('98f2bc8e61'));
}

if (b.and(new BigInteger('2')).intValue()) {
v = v.xor(BigInteger.fromHex('79b76d99e2'));
}

if (b.and(new BigInteger('4')).intValue()) {
v = v.xor(BigInteger.fromHex('f33e5fb3c4'));
}

if (b.and(new BigInteger('8')).intValue()) {
v = v.xor(BigInteger.fromHex('ae2eabe2a8'));
}

if (b.and(new BigInteger('16')).intValue()) {
v = v.xor(BigInteger.fromHex('1e4f43e470'));
}

return v;
}

function prefixChk(prefix) {
var chk = new BigInteger('1');

for (var i = 0; i < prefix.length; ++i) {
var c = prefix.charCodeAt(i);
var mixwith = new BigInteger('' + (c & 0x1f));
chk = polymodStep(chk).xor(mixwith);
}

chk = polymodStep(chk);
return chk;
}

function encode(prefix, words) {
// too long?
if (prefix.length + CSLEN + 1 + words.length > 90) {
throw new TypeError('Exceeds Base32 maximum length');
}

prefix = prefix.toLowerCase(); // determine chk mod
} // pre defined BigInt could faster about 40 percent


var BIGINT_0 = JSBI.BigInt(0);
var BIGINT_1 = JSBI.BigInt(1);
var BIGINT_5 = JSBI.BigInt(5);
var BIGINT_35 = JSBI.BigInt(35);
var BIGINT_0B00001 = JSBI.BigInt(1);
var BIGINT_0B00010 = JSBI.BigInt(2);
var BIGINT_0B00100 = JSBI.BigInt(4);
var BIGINT_0B01000 = JSBI.BigInt(8);
var BIGINT_0B10000 = JSBI.BigInt(16);
var BIGINT_0X07FFFFFFFF = JSBI.BigInt(0x07ffffffff);
var BIGINT_0X98F2BC8E61 = JSBI.BigInt(0x98f2bc8e61);
var BIGINT_0X79B76D99E2 = JSBI.BigInt(0x79b76d99e2);
var BIGINT_0XF33E5FB3C4 = JSBI.BigInt(0xf33e5fb3c4);
var BIGINT_0XAE2EABE2A8 = JSBI.BigInt(0xae2eabe2a8);
var BIGINT_0X1E4F43E470 = JSBI.BigInt(0x1e4f43e470);

function convertBit(buffer, inBits, outBits, pad) {
var mask = (1 << outBits) - 1;
var array = [];
var bits = 0;
var value = 0;

var chk = prefixChk(prefix);
var result = prefix + SEPARATOR;
var _iterator = _createForOfIteratorHelper(buffer),
_step;

for (var i = 0; i < words.length; ++i) {
var _x = words[i];
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var _byte = _step.value;
bits += inBits;
value = value << inBits | _byte;

if (_x >>> 5 !== 0) {
throw new Error('Non 5-bit word');
while (bits >= outBits) {
bits -= outBits;
array.push(value >>> bits & mask);
}
}

chk = polymodStep(chk).xor(new BigInteger('' + _x));
result += ALPHABET.charAt(_x);
}

for (var _i = 0; _i < CSLEN; ++_i) {
chk = polymodStep(chk);
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}

chk = chk.xor(new BigInteger('1'));
value = value << outBits - bits & mask;

for (var _i2 = 0; _i2 < CSLEN; ++_i2) {
var pos = 5 * (CSLEN - 1 - _i2);
var v2 = chk.shiftRight(new BigInteger('' + pos)).and(BigInteger.fromHex('1f'));
result += ALPHABET.charAt(v2.toString(10));
if (bits && pad) {
array.push(value);
} else if (value && !pad) {
throw new Error('Excess padding');
} else if (bits >= inBits && !pad) {
throw new Error('Non-zero padding');
}

return result;
return array;
}

function decode(str) {
if (str.length < 8) {
throw new TypeError(str + ' too short');
}
function polyMod(buffer) {
var checksumBigInt = BIGINT_1;

if (str.length > 90) {
throw new TypeError(str + ' too long');
} // don't allow mixed case
var _iterator2 = _createForOfIteratorHelper(buffer),
_step2;

try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var _byte2 = _step2.value;
// c0 = c >> 35;
var high = JSBI.signedRightShift(checksumBigInt, BIGINT_35); // XXX: checksumBigInt must be positive, signedRightShift is ok
// c = ((c & 0x07ffffffff) << 5) ^ d;

var lowered = str.toLowerCase();
var uppered = str.toUpperCase();
checksumBigInt = JSBI.bitwiseAnd(checksumBigInt, BIGINT_0X07FFFFFFFF);
checksumBigInt = JSBI.leftShift(checksumBigInt, BIGINT_5);
checksumBigInt = _byte2 ? JSBI.bitwiseXor(checksumBigInt, JSBI.BigInt(_byte2)) : checksumBigInt; // bit ^ 0 = bit

if (str !== lowered && str !== uppered) {
throw new Error('Mixed-case string ' + str);
}
if (JSBI.notEqual(JSBI.bitwiseAnd(high, BIGINT_0B00001), BIGINT_0)) {
checksumBigInt = JSBI.bitwiseXor(checksumBigInt, BIGINT_0X98F2BC8E61);
}

str = lowered;
var split = str.lastIndexOf(SEPARATOR);
if (JSBI.notEqual(JSBI.bitwiseAnd(high, BIGINT_0B00010), BIGINT_0)) {
checksumBigInt = JSBI.bitwiseXor(checksumBigInt, BIGINT_0X79B76D99E2);
}

if (split === -1) {
throw new Error('No separator character for ' + str);
}
if (JSBI.notEqual(JSBI.bitwiseAnd(high, BIGINT_0B00100), BIGINT_0)) {
checksumBigInt = JSBI.bitwiseXor(checksumBigInt, BIGINT_0XF33E5FB3C4);
}

if (split === 0) {
throw new Error('Missing prefix for ' + str);
}

var prefix = str.slice(0, split);
var wordChars = str.slice(split + 1);

if (wordChars.length < 6) {
throw new Error('Data too short');
}

var chk = prefixChk(prefix);
var words = [];

for (var i = 0; i < wordChars.length; ++i) {
var c = wordChars.charAt(i);
var v = ALPHABET_MAP[c];

if (v === undefined) {
throw new Error('Unknown character ' + c);
}
if (JSBI.notEqual(JSBI.bitwiseAnd(high, BIGINT_0B01000), BIGINT_0)) {
checksumBigInt = JSBI.bitwiseXor(checksumBigInt, BIGINT_0XAE2EABE2A8);
}

chk = polymodStep(chk).xor(new BigInteger('' + v)); // not in the checksum?

if (i + CSLEN >= wordChars.length) {
continue;
if (JSBI.notEqual(JSBI.bitwiseAnd(high, BIGINT_0B10000), BIGINT_0)) {
checksumBigInt = JSBI.bitwiseXor(checksumBigInt, BIGINT_0X1E4F43E470);
}
}

words.push(v);
}

if (chk.toString(10) !== '1') {
throw new Error('Invalid checksum for ' + str);
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}

return {
prefix: prefix,
words: words
};
}

function convert(data, inBits, outBits, pad) {
var value = 0;
var bits = 0;
var maxV = (1 << outBits) - 1;
var result = [];

for (var i = 0; i < data.length; ++i) {
value = value << inBits | data[i];
bits += inBits;

while (bits >= outBits) {
bits -= outBits;
result.push(value >>> bits & maxV);
}
}

if (pad) {
if (bits > 0) {
result.push(value << outBits - bits & maxV);
}
} else {
if (bits >= inBits) {
throw new Error('Excess padding');
}

if (value << outBits - bits & maxV) {
throw new Error('Non-zero padding');
}
}

return result;
}

function toWords(bytes) {
return convert(bytes, 8, 5, true);
}

function fromWords(words) {
return convert(words, 5, 8, false);
return JSBI.bitwiseXor(checksumBigInt, BIGINT_1);
}

module.exports = {
decode: decode,
encode: encode,
toWords: toWords,
fromWords: fromWords
convertBit: convertBit,
polyMod: polyMod,
ALPHABET: ALPHABET,
ALPHABET_MAP: ALPHABET_MAP
};
Loading