UNPKG

@iota/kerl

Version:

IOTA-related cryptographic methods

278 lines 7.25 kB
"use strict"; exports.__esModule = true; var errors = require("./errors"); /* tslint:disable variable-name */ var INT_LENGTH = 12; var RADIX = 3; // hex representation of (3^242)/2 var HALF_3 = new Uint32Array([ 0xa5ce8964, 0x9f007669, 0x1484504f, 0x3ade00d9, 0x0c24486e, 0x50979d57, 0x79a4c702, 0x48bbae36, 0xa9f6808b, 0xaa06a805, 0xa87fabdf, 0x5e69ebef, ]); function clone_uint32Array(array) { var source = new Uint32Array(array); return new Uint32Array(source); } function ta_slice(array) { if (array.slice !== undefined) { return array.slice(); } return clone_uint32Array(array); } function ta_reverse(array) { if (array.reverse !== undefined) { array.reverse(); return; } var n = array.length; var middle = Math.floor(n / 2); var i = 0; var temp = null; for (; i < middle; i += 1) { temp = array[i]; array[i] = array[n - 1 - i]; array[n - 1 - i] = temp; } } // negates the (unsigned) input array function bigint_not(arr) { for (var i = 0; i < arr.length; i++) { arr[i] = ~arr[i] >>> 0; } } // rshift that works with up to 53 // JS's shift operators only work on 32 bit integers // ours is up to 33 or 34 bits though, so // we need to implement shifting manually function rshift(num, shift) { return (num / Math.pow(2, shift)) >>> 0; } // swaps endianness function swap32(val) { return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | ((val >> 8) & 0xff00) | ((val >> 24) & 0xff); } // add with carry function full_add(lh, rh, carry) { var v = lh + rh; var l = rshift(v, 32) & 0xffffffff; var r = (v & 0xffffffff) >>> 0; var carry1 = l !== 0; if (carry) { v = r + 1; } l = rshift(v, 32) & 0xffffffff; r = (v & 0xffffffff) >>> 0; var carry2 = l !== 0; return [r, carry1 || carry2]; } // subtracts rh from base function bigint_sub(base, rh) { var noborrow = true; for (var i = 0; i < base.length; i++) { var vc = full_add(base[i], ~rh[i] >>> 0, noborrow); base[i] = vc[0]; noborrow = vc[1]; } if (!noborrow) { throw new Error('noborrow'); } } // compares two (unsigned) big integers function bigint_cmp(lh, rh) { for (var i = lh.length; i-- > 0;) { var a = lh[i] >>> 0; var b = rh[i] >>> 0; if (a < b) { return -1; } else if (a > b) { return 1; } } return 0; } // adds rh to base in place function bigint_add(base, rh) { var carry = false; for (var i = 0; i < base.length; i++) { var vc = full_add(base[i], rh[i], carry); base[i] = vc[0]; carry = vc[1]; } } function is_null(arr) { // tslint:disable-next-line prefer-for-of for (var i = 0; i < arr.length; i++) { if (arr[i] !== 0) { return false; } } return true; } // adds a small (i.e. <32bit) number to base function bigint_add_small(base, other) { var vc = full_add(base[0], other, false); var carry; base[0] = vc[0]; carry = vc[1]; var i = 1; while (carry && i < base.length) { var vc2 = full_add(base[i], 0, carry); base[i] = vc2[0]; carry = vc2[1]; i += 1; } return i; } /** * Converts the given byte array to trits * * @method wordsToTrits * * @ignore * * @param {Uint32Array} words * * @return {Int8Array} trits */ function wordsToTrits(words) { if (words.length !== INT_LENGTH) { throw new Error(errors.ILLEGAL_WORDS_LENGTH); } var trits = new Int8Array(243); var base = new Uint32Array(words); ta_reverse(base); var flip_trits = false; if (base[INT_LENGTH - 1] >> 31 === 0) { // positive two's complement number. // add HALF_3 to move it to the right place. bigint_add(base, HALF_3); } else { // negative number. bigint_not(base); if (bigint_cmp(base, HALF_3) > 0) { bigint_sub(base, HALF_3); flip_trits = true; } else { /// bigint is between (unsigned) HALF_3 and (2**384 - 3**242/2). bigint_add_small(base, 1); var tmp = ta_slice(HALF_3); bigint_sub(tmp, base); base = tmp; } } var rem = 0; for (var i = 0; i < 242; i++) { rem = 0; for (var j = INT_LENGTH - 1; j >= 0; j--) { var lhs = (rem !== 0 ? rem * 0xffffffff + rem : 0) + base[j]; var rhs = RADIX; var q = (lhs / rhs) >>> 0; var r = (lhs % rhs) >>> 0; base[j] = q; rem = r; } trits[i] = rem - 1; } if (flip_trits) { for (var i = 0; i < trits.length; i++) { trits[i] = -trits[i]; } } return trits; } exports.wordsToTrits = wordsToTrits; /** * Converts the given trits to byte array * * @method tritsToWords * * @ignore * * @param {Int8Array} trits * * @return {Uint32Array} words */ function tritsToWords(trits) { if (trits.length !== 243) { throw new Error('Invalid trits length'); } var base = new Uint32Array(INT_LENGTH); var allMinusOne = true; var tritSlice = trits.slice(0, 242); for (var i = 0; i < tritSlice.length; i++) { if (tritSlice[i] !== -1) { allMinusOne = false; break; } } if (allMinusOne) { base = ta_slice(HALF_3); bigint_not(base); bigint_add_small(base, 1); } else { var size = 1; for (var i = trits.length - 1; i-- > 0;) { var trit = trits[i] + 1; // multiply by radix { var sz = size; var carry = 0; for (var j = 0; j < sz; j++) { var v = base[j] * RADIX + carry; carry = rshift(v, 32); base[j] = (v & 0xffffffff) >>> 0; } if (carry > 0) { base[sz] = carry; size += 1; } } // addition { var sz = bigint_add_small(base, trit); if (sz > size) { size = sz; } } } if (!is_null(base)) { if (bigint_cmp(HALF_3, base) <= 0) { // base >= HALF_3 // just do base - HALF_3 bigint_sub(base, HALF_3); } else { // base < HALF_3 // so we need to transform it to a two's complement representation // of (base - HALF_3). // as we don't have a wrapping (-), we need to use some bit magic var tmp = ta_slice(HALF_3); bigint_sub(tmp, base); bigint_not(tmp); bigint_add_small(tmp, 1); base = tmp; } } } ta_reverse(base); for (var i = 0; i < base.length; i++) { base[i] = swap32(base[i]); } return base; } exports.tritsToWords = tritsToWords; //# sourceMappingURL=word-converter.js.map