blob: ed93ead8c1ba166719016816478e70273263000a [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/**
* @fileoverview Utilities for manipulating bytes.
* @private
*/
module.exports = {
emptyOrAllZero: emptyOrAllZero,
allOne: allOne,
shiftLeftOne: shiftLeftOne,
shiftRightOne: shiftRightOne,
twosComplement: twosComplement,
decrement: decrement,
increment: increment,
bytes2Hex: bytes2Hex,
hex2Bytes: hex2Bytes
};
/**
* Checks if the array of bytes is all zero or empty.
* @private
* @param {Uint8Array} bytes the input byte array.
* @return {boolean} true if the array is all zero or empty. false otherwise.
*/
function emptyOrAllZero(bytes) {
for (var i = 0; i < bytes.length; i++) {
if (bytes[i] !== 0x00) {
return false;
}
}
return true;
}
/**
* Checks if the array of bytes is all one bits (0xff bytes).
* @private
* @param {Uint8Array} bytes the input byte array.
* @return {boolean} true if the array is all one. false otherwise.
*/
function allOne(bytes) {
if (bytes.length === 0) {
return false;
}
for (var i = 0; i < bytes.length; i++) {
if (bytes[i] !== 0xff) {
return false;
}
}
return true;
}
/**
* Shifts the bytes to the left by one bit.
* This may mutate the input array.
* @private
* @param {Uint8Array} bytes the input byte array.
* @return the left shifted byte array.
*/
function shiftLeftOne(bytes) {
if (emptyOrAllZero(bytes)) {
return bytes;
}
if ((bytes[0] & 0x80) !== 0) {
// Expand the array because the shift will lose the upper bit.
var largerArray = new Uint8Array(bytes.length + 1);
largerArray.set(bytes, 1);
bytes = largerArray;
}
for (var i = 0; i < bytes.length - 1; i++) {
var val = bytes[i] << 1;
val = val | (bytes[i + 1] & 0x80) >>> 7;
bytes[i] = val;
}
bytes[bytes.length - 1] = bytes[bytes.length - 1] << 1;
return bytes;
}
/**
* Shifts the bytes to the right by one bit.
* This mutates the input array.
* @private
* @param {Uint8Array} bytes the input byte array.
* @return the right shifted byte array.
*/
function shiftRightOne(bytes) {
var topBit = 0;
for (var i = 0; i < bytes.length; i++) {
var nextTopBit = (bytes[i] & 0x01) << 7;
bytes[i] = (bytes[i] >>> 1) | topBit;
topBit = nextTopBit;
}
return bytes;
}
/**
* Computes the two's complement of the value in the byte array.
* @private
* @param {Uint8Array} bytes the input byte array.
* @return the two's complemented byte array
*/
function twosComplement(bytes) {
var flipped = false;
for (var i = bytes.length - 1; i >= 0; i--) {
if (flipped) {
bytes[i] = ~bytes[i];
} else {
if (bytes[i] !== 0) {
bytes[i] = 0x100 - bytes[i];
flipped = true;
}
}
}
return bytes;
}
/**
* Decrements the input byte array by 1.
* This mutates the input array.
* @private
* @param {Uint8Array} bytes the input byte array.
* @return the decremented byte array.
*/
function decrement(bytes) {
if (emptyOrAllZero(bytes)) {
throw new Error('Decrement of zero not supported');
}
for (var i = bytes.length - 1; i >= 0; i--) {
if (bytes[i] === 0) {
bytes[i] = 0xff;
} else {
bytes[i] = bytes[i] - 1;
break;
}
}
return bytes;
}
/**
* Increments the input byte array by 1.
* This mutates the input array.
* @private
* @param {Uint8Array} bytes the input byte array.
* @return the incremented byte array.
*/
function increment(bytes) {
if (bytes.length === 0) {
return new Uint8Array([0x01]);
}
if (allOne(bytes)) {
// Expand the array because the shift will lose the upper bit.
var largerArray = new Uint8Array(bytes.length + 1);
largerArray.set(bytes, 1);
bytes = largerArray;
}
for (var i = bytes.length - 1; i >= 0; i--) {
if (bytes[i] === 0xff) {
bytes[i] = 0x00;
} else {
bytes[i] = bytes[i] + 1;
break;
}
}
return bytes;
}
/**
* Converts the input byte array to a hex representation.
* @private
* @param {Uint8Array} bytes the input byte array.
* @return {string} a hex string representation of the input array.
*/
function bytes2Hex(arr) {
var hexString = '';
for (var i = 0; i < arr.length; i++) {
var str = arr[i].toString(16);
if (str.length === 1) {
str = '0' + str;
}
hexString += str;
}
return hexString;
}
/**
* Converts the input hex string to a byte array.
* @private
* @param {string} hexString the input hex string.
* @return {Uint8Array} the byte array representation of the hex string.
*/
function hex2Bytes(hexString) {
if (hexString.length % 2 !== 0) {
throw new Error('Even length string required.');
}
var arr = new Uint8Array(hexString.length / 2);
for (var i = 0; i < arr.length; i++) {
arr[i] = parseInt(hexString.substring(i*2, (i+1)*2), 16);
}
return arr;
}