Skip to content
Permalink
Browse files
Fix LE constructor for HEX (#265)
  • Loading branch information
fanatid committed Feb 23, 2021
1 parent c89be2c commit 3f3115171da396f959b113cdfed6e5038c6f1298
Showing with 73 additions and 62 deletions.
  1. +62 −59 lib/bn.js
  2. +11 −3 test/constructor-test.js
121 lib/bn.js
@@ -91,23 +91,19 @@
var start = 0;
if (number[0] === '-') {
start++;
}

if (base === 16) {
this._parseHex(number, start);
} else {
this._parseBase(number, base, start);
}

if (number[0] === '-') {
this.negative = 1;
}

this._strip();

if (endian !== 'le') return;

this._initArray(this.toArray(), base, endian);
if (start < number.length) {
if (base === 16) {
this._parseHex(number, start, endian);
} else {
this._parseBase(number, base, start);
if (endian === 'le') {
this._initArray(this.toArray(), base, endian);
}
}
}
};

BN.prototype._initNumber = function _initNumber (number, base, endian) {
@@ -183,65 +179,70 @@
return this._strip();
};

function parseHex (str, start, end) {
var r = 0;
var len = Math.min(str.length, end);
var z = 0;
for (var i = start; i < len; i++) {
var c = str.charCodeAt(i) - 48;

r <<= 4;

var b;

// 'a' - 'f'
if (c >= 49 && c <= 54) {
b = c - 49 + 0xa;

// 'A' - 'F'
} else if (c >= 17 && c <= 22) {
b = c - 17 + 0xa;

// '0' - '9'
} else {
b = c;
}

r |= b;
z |= b;
function parseHex4Bits (string, index) {
var c = string.charCodeAt(index);
// '0' - '9'
if (c >= 48 && c <= 57) {
return c - 48;
// 'A' - 'F'
} else if (c >= 65 && c <= 70) {
return c - 55;
// 'a' - 'f'
} else if (c >= 97 && c <= 102) {
return c - 87;
} else {
assert(false, 'Invalid character in ' + string);
}
}

assert(!(z & 0xf0), 'Invalid character in ' + str);
function parseHexByte (string, lowerBound, index) {
var r = parseHex4Bits(string, index);
if (index - 1 >= lowerBound) {
r |= parseHex4Bits(string, index - 1) << 4;
}
return r;
}

BN.prototype._parseHex = function _parseHex (number, start) {
BN.prototype._parseHex = function _parseHex (number, start, endian) {
// Create possibly bigger array to ensure that it fits the number
this.length = Math.ceil((number.length - start) / 6);
this.words = new Array(this.length);
for (var i = 0; i < this.length; i++) {
this.words[i] = 0;
}

var j, w;
// Scan 24-bit chunks and add them to the number
// 24-bits chunks
var off = 0;
for (i = number.length - 6, j = 0; i >= start; i -= 6) {
w = parseHex(number, i, i + 6);
this.words[j] |= (w << off) & 0x3ffffff;
// NOTE: `0x3fffff` is intentional here, 26bits max shift + 24bit hex limb
this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;
off += 24;
if (off >= 26) {
off -= 26;
j++;
}
}
if (i + 6 !== start) {
w = parseHex(number, start, i + 6);
this.words[j] |= (w << off) & 0x3ffffff;
this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;
var j = 0;

var w;
if (endian === 'be') {
for (i = number.length - 1; i >= start; i -= 2) {
w = parseHexByte(number, start, i) << off;
this.words[j] |= w & 0x3ffffff;
if (off >= 18) {
off -= 18;
j += 1;
this.words[j] |= w >>> 26;
} else {
off += 8;
}
}
} else {
var parseLength = number.length - start;
for (i = parseLength % 2 === 0 ? start + 1 : start; i < number.length; i += 2) {
w = parseHexByte(number, start, i) << off;
this.words[j] |= w & 0x3ffffff;
if (off >= 18) {
off -= 18;
j += 1;
this.words[j] |= w >>> 26;
} else {
off += 8;
}
}
}

this._strip();
};

@@ -315,6 +316,8 @@
this._iaddn(word);
}
}

this._strip();
};

BN.prototype.copy = function copy (dest) {
@@ -91,6 +91,12 @@ describe('BN.js/Constructor', function () {
'df8c5d766b1a');
});

it('should accept base-16 LE integer with leading zeros', function () {
assert.equal(new BN('0010', 16, 'le').toNumber(), 4096);
assert.equal(new BN('-010', 16, 'le').toNumber(), -4096);
assert.equal(new BN('010', 16, 'le').toNumber(), 4096);
});

it('should not accept wrong characters for base', function () {
assert.throws(function () {
return new BN('01FF');
@@ -131,6 +137,7 @@ describe('BN.js/Constructor', function () {
});

it('should import/export big endian', function () {
assert.equal(new BN([0, 1], 16).toString(16), '1');
assert.equal(new BN([1, 2, 3]).toString(16), '10203');
assert.equal(new BN([1, 2, 3, 4]).toString(16), '1020304');
assert.equal(new BN([1, 2, 3, 4, 5]).toString(16), '102030405');
@@ -142,9 +149,10 @@ describe('BN.js/Constructor', function () {
});

it('should import little endian', function () {
assert.equal(new BN([1, 2, 3], 10, 'le').toString(16), '30201');
assert.equal(new BN([1, 2, 3, 4], 10, 'le').toString(16), '4030201');
assert.equal(new BN([1, 2, 3, 4, 5], 10, 'le').toString(16),
assert.equal(new BN([0, 1], 16, 'le').toString(16), '100');
assert.equal(new BN([1, 2, 3], 16, 'le').toString(16), '30201');
assert.equal(new BN([1, 2, 3, 4], 16, 'le').toString(16), '4030201');
assert.equal(new BN([1, 2, 3, 4, 5], 16, 'le').toString(16),
'504030201');
assert.equal(new BN([1, 2, 3, 4, 5, 6, 7, 8], 'le').toString(16),
'807060504030201');

0 comments on commit 3f31151

Please sign in to comment.