/** @fileOverview Arrays of bits, encoded as arrays of Numbers. * * @author Emily Stark * @author Mike Hamburg * @author Dan Boneh */ /** @namespace Arrays of bits, encoded as arrays of Numbers. * * @description *
* These objects are the currency accepted by SJCL's crypto functions. *
* ** Most of our crypto primitives operate on arrays of 4-byte words internally, * but many of them can take arguments that are not a multiple of 4 bytes. * This library encodes arrays of bits (whose size need not be a multiple of 8 * bits) as arrays of 32-bit words. The bits are packed, big-endian, into an * array of words, 32 bits at a time. Since the words are double-precision * floating point numbers, they fit some extra data. We use this (in a private, * possibly-changing manner) to encode the number of bits actually present * in the last word of the array. *
* ** Because bitwise ops clear this out-of-band data, these arrays can be passed * to ciphers like AES which want arrays of words. *
*/ sjcl.bitArray = { /** * Array slices in units of bits. * @param {bitArray a} The array to slice. * @param {Number} bstart The offset to the start of the slice, in bits. * @param {Number} bend The offset to the end of the slice, in bits. If this is undefined, * slice until the end of the array. * @return {bitArray} The requested slice. */ bitSlice: function (a, bstart, bend) { a = sjcl.bitArray._shiftRight(a.slice(bstart/32), 32 - (bstart & 31)).slice(1); return (bend === undefined) ? a : sjcl.bitArray.clamp(a, bend-bstart); }, /** * Concatenate two bit arrays. * @param {bitArray} a1 The first array. * @param {bitArray} a2 The second array. * @return {bitArray} The concatenation of a1 and a2. */ concat: function (a1, a2) { if (a1.length === 0 || a2.length === 0) { return a1.concat(a2); } var out, i, last = a1[a1.length-1], shift = sjcl.bitArray.getPartial(last); if (shift === 32) { return a1.concat(a2); } else { return sjcl.bitArray._shiftRight(a2, shift, last|0, a1.slice(0,a1.length-1)); } }, /** * Find the length of an array of bits. * @param {bitArray} a The array. * @return {Number} The length of a, in bits. */ bitLength: function (a) { var l = a.length, x; if (l === 0) { return 0; } x = a[l - 1]; return (l-1) * 32 + sjcl.bitArray.getPartial(x); }, /** * Truncate an array. * @param {bitArray} a The array. * @param {Number} len The length to truncate to, in bits. * @return {bitArray} A new array, truncated to len bits. */ clamp: function (a, len) { if (a.length * 32 < len) { return a; } a = a.slice(0, Math.ceil(len / 32)); var l = a.length; len = len & 31; if (l > 0 && len) { a[l-1] = sjcl.bitArray.partial(len, a[l-1] & 0x80000000 >> (len-1), 1); } return a; }, /** * Make a partial word for a bit array. * @param {Number} len The number of bits in the word. * @param {Number} x The bits. * @param {Number} [0] _end Pass 1 if x has already been shifted to the high side. * @return {Number} The partial word. */ partial: function (len, x, _end) { if (len === 32) { return x; } return (_end ? x|0 : x << (32-len)) + len * 0x10000000000; }, /** * Get the number of bits used by a partial word. * @param {Number} x The partial word. * @return {Number} The number of bits used by the partial word. */ getPartial: function (x) { return Math.round(x/0x10000000000) || 32; }, /** * Compare two arrays for equality in a predictable amount of time. * @param {bitArray} a The first array. * @param {bitArray} b The second array. * @return {boolean} true if a == b; false otherwise. */ equal: function (a, b) { if (sjcl.bitArray.bitLength(a) !== sjcl.bitArray.bitLength(b)) { return false; } var x = 0, i; for (i=0; i