var crypto = require('crypto'); var bignum = require('bignum'); var globalBuffer = new Buffer(1024); var zerobuf = new Buffer(0); var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; var ALPHABET_ZERO = ALPHABET[0]; var ALPHABET_BUF = new Buffer(ALPHABET, 'ascii'); var ALPHABET_INV = {}; for (var i = 0; i < ALPHABET.length; i++) { ALPHABET_INV[ALPHABET[i]] = i; }; // Vanilla Base58 Encoding var base58 = { encode: function(buf) { var str; var x = bignum.fromBuffer(buf); var r; if (buf.length < 512) { str = globalBuffer; } else { str = new Buffer(buf.length << 1); } var i = str.length - 1; while (x.gt(0)) { r = x.mod(58); x = x.div(58); str[i] = ALPHABET_BUF[r.toNumber()]; i--; } // deal with leading zeros var j = 0; while (buf[j] == 0) { str[i] = ALPHABET_BUF[0]; j++; i--; } return str.slice(i + 1, str.length).toString('ascii'); }, decode: function(str) { if (str.length == 0) return zerobuf; var answer = bignum(0); for (var i = 0; i < str.length; i++) { answer = answer.mul(58); answer = answer.add(ALPHABET_INV[str[i]]); }; var i = 0; while (i < str.length && str[i] == ALPHABET_ZERO) { i++; } if (i > 0) { var zb = new Buffer(i); zb.fill(0); if (i == str.length) return zb; answer = answer.toBuffer(); return Buffer.concat([zb, answer], i + answer.length); } else { return answer.toBuffer(); } }, }; // Base58Check Encoding function sha256(data) { return new Buffer(crypto.createHash('sha256').update(data).digest('binary'), 'binary'); }; function doubleSHA256(data) { return sha256(sha256(data)); }; var base58Check = { encode: function(buf) { var checkedBuf = new Buffer(buf.length + 4); var hash = doubleSHA256(buf); buf.copy(checkedBuf); hash.copy(checkedBuf, buf.length); return base58.encode(checkedBuf); }, decode: function(s) { var buf = base58.decode(s); if (buf.length < 4) { throw new Error("invalid input: too short"); } var data = buf.slice(0, -4); var csum = buf.slice(-4); var hash = doubleSHA256(data); var hash4 = hash.slice(0, 4); if (csum.toString('hex') !== hash4.toString('hex')) { throw new Error("checksum mismatch"); } return data; }, }; // if you frequently do base58 encodings with data larger // than 512 bytes, you can use this method to expand the // size of the reusable buffer exports.setBuffer = function(buf) { globalBuffer = buf; }; exports.base58 = base58; exports.base58Check = base58Check; exports.encode = base58.encode; exports.decode = base58.decode;