Merge pull request #136 from pointbiz/biginteger-fixes
BigInteger modInverse should be positive
This commit is contained in:
commit
834aad72d2
5 changed files with 476 additions and 20 deletions
|
@ -28,6 +28,14 @@ END USER NOTES:
|
|||
|
||||
Here is a signed list of file names and version history.
|
||||
|
||||
2016-07-31: status ACTIVE
|
||||
bitaddress.org-v3.2.1-SHA256-.html
|
||||
- BigInteger modInverse should be positive
|
||||
- throw if modInverse 0
|
||||
- improve BigInteger constructor so that it works if caller forgets 'new'
|
||||
- add unit tests for BigInteger
|
||||
- thanks to dooglus, jprichardson, dcousens
|
||||
|
||||
2016-02-19: status ACTIVE
|
||||
bitaddress.org-v3.2.0-SHA256-ad4fd171c647772aa76d0ce828731b01ca586596275d43a94008766b758e8736.html
|
||||
- switch languages without full page load
|
||||
|
|
|
@ -2878,8 +2878,12 @@ exports.init();
|
|||
})(typeof module !== 'undefined' && module['exports'] ? module['exports'] : (window['secrets'] = {}), typeof GLOBAL !== 'undefined' ? GLOBAL : window );
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
// Upstream 'BigInteger' here:
|
||||
// Original Author: http://www-cs-students.stanford.edu/~tjw/jsbn/
|
||||
// Follows 'jsbn' on Github: https://github.com/jasondavies/jsbn
|
||||
// Review and Testing: https://github.com/cryptocoinjs/bigi/
|
||||
/*!
|
||||
* Basic JavaScript BN library - subset useful for RSA encryption. v1.3
|
||||
* Basic JavaScript BN library - subset useful for RSA encryption. v1.4
|
||||
*
|
||||
* Copyright (c) 2005 Tom Wu
|
||||
* All Rights Reserved.
|
||||
|
@ -2887,13 +2891,16 @@ exports.init();
|
|||
* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
|
||||
*
|
||||
* Copyright Stephan Thomas
|
||||
* Copyright bitaddress.org
|
||||
* Copyright pointbiz
|
||||
*/
|
||||
|
||||
(function () {
|
||||
|
||||
// (public) Constructor function of Global BigInteger object
|
||||
var BigInteger = window.BigInteger = function BigInteger(a, b, c) {
|
||||
if (!(this instanceof BigInteger))
|
||||
return new BigInteger(a, b, c);
|
||||
|
||||
if (a != null)
|
||||
if ("number" == typeof a) this.fromNumber(a, b, c);
|
||||
else if (b == null && "string" != typeof a) this.fromString(a, 256);
|
||||
|
@ -3824,6 +3831,7 @@ exports.init();
|
|||
// (public) 1/this % m (HAC 14.61)
|
||||
BigInteger.prototype.modInverse = function (m) {
|
||||
var ac = m.isEven();
|
||||
if (this.signum() === 0) throw new Error('division by zero');
|
||||
if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
|
||||
var u = m.clone(), v = this.clone();
|
||||
var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
|
||||
|
@ -3858,9 +3866,9 @@ exports.init();
|
|||
}
|
||||
}
|
||||
if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
|
||||
if (d.compareTo(m) >= 0) return d.subtract(m);
|
||||
if (d.signum() < 0) d.addTo(m, d); else return d;
|
||||
if (d.signum() < 0) return d.add(m); else return d;
|
||||
while (d.compareTo(m) >= 0) d.subTo(m, d);
|
||||
while (d.signum() < 0) d.addTo(m, d);
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
|
@ -7025,7 +7033,7 @@ input[type=checkbox] { position: relative; z-index: 20; }
|
|||
<div class="tooltip" id="statusprotocolbad">
|
||||
<span class="statuswarn" id="statuslabelprotocolbad">⚠ Think twice!</span>
|
||||
<span id="statuslabelprotocolbad1">You appear to be running this generator online from a live website. For valuable wallets it is recommended to</span>
|
||||
<a id="statuslabelprotocolbad2" href="https://github.com/pointbiz/bitaddress.org/archive/v3.2.0.zip">download</a>
|
||||
<a id="statuslabelprotocolbad2" href="https://github.com/pointbiz/bitaddress.org/archive/v3.2.1.zip">download</a>
|
||||
<span id="statuslabelprotocolbad3">the zip file from GitHub and run this generator offline as a local html file.</span>
|
||||
<br /><br /><input type="button" value="OK" class="button" id="statusokprotocolbad" onclick="document.getElementById('statusprotocolbad').style.display = 'none';" />
|
||||
</div>
|
||||
|
@ -7050,12 +7058,12 @@ input[type=checkbox] { position: relative; z-index: 20; }
|
|||
<span class="item"><span id="footerlabeldonations">Donations:</span> <b>1NiNja</b>1bUmhSoTXozBRBEtR8LeF9TGbZBN</span>
|
||||
<span class="item" id="footerlabeltranslatedby"></span>
|
||||
<span class="item"><a href="https://github.com/pointbiz/bitaddress.org" target="_blank" id="footerlabelgithub">GitHub Repository</a>
|
||||
(<a href="https://github.com/pointbiz/bitaddress.org/archive/v3.2.0.zip" target="_blank" id="footerlabelgithubzip">zip</a>)</span>
|
||||
(<a href="https://github.com/pointbiz/bitaddress.org/archive/v3.2.1.zip" target="_blank" id="footerlabelgithubzip">zip</a>)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="authorpgp">
|
||||
<span class="item">
|
||||
<a href="CHANGELOG.txt.asc" target="_blank"><span id="footerlabelversion">Version History</span> (3.2.0)</a>
|
||||
<a href="CHANGELOG.txt.asc" target="_blank"><span id="footerlabelversion">Version History</span> (3.2.1)</a>
|
||||
|
||||
</span>
|
||||
<span class="item">527B 5C82 B1F6 B2DB 72A0<br />ECBF 8749 7B91 6397 4F5A</span>
|
||||
|
@ -10817,7 +10825,7 @@ ninja.wallets.splitwallet = {
|
|||
}
|
||||
testResults += passCount + " of " + testCount + " synchronous tests passed";
|
||||
if (passCount < testCount) {
|
||||
testResults += "<b>" + (testCount - passCount) + " unit test(s) failed</b>";
|
||||
testResults += "<br/><b>" + (testCount - passCount) + " unit test(s) failed</b>";
|
||||
}
|
||||
if (showOutput) {
|
||||
div.innerHTML = "<h3>Unit Tests</h3><div id=\"unittestresults\">" + testResults + "<br/><br/></div>";
|
||||
|
@ -11406,7 +11414,223 @@ ninja.wallets.splitwallet = {
|
|||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
//BigInteger tests
|
||||
testBigIntegerShouldWorkWithoutNew: function () {
|
||||
var bi = BigInteger('12345')
|
||||
if (bi.toString(10) != '12345') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldWorkWithStringInput: function () {
|
||||
if (new BigInteger('12345').toString(16) != '3039') return false;
|
||||
if (new BigInteger('29048849665247').toString(16) != '1a6b765d8cdf') return false;
|
||||
if (new BigInteger('-29048849665247').toString(16) != '-1a6b765d8cdf') return false;
|
||||
if (new BigInteger('1A6B765D8CDF', 16).toString(16) != '1a6b765d8cdf') return false;
|
||||
if (new BigInteger('FF', 16).toString() != '255') return false;
|
||||
if (new BigInteger('1A6B765D8CDF', 16).toString() != '29048849665247') return false;
|
||||
if (new BigInteger('a89c e5af8724 c0a23e0e 0ff77500', 16).toString(16) != 'a89ce5af8724c0a23e0e0ff77500') return false;
|
||||
if (new BigInteger('123456789abcdef123456789abcdef123456789abcdef', 16).toString(16) != '123456789abcdef123456789abcdef123456789abcdef') return false;
|
||||
if (new BigInteger('10654321').toString() != '10654321') return false;
|
||||
if (new BigInteger('10000000000000000').toString(10) != '10000000000000000') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldImportExportTwosComplementBigEndian: function () {
|
||||
if (new BigInteger([1, 2, 3], 256).toString(16) != '10203') return false;
|
||||
if (new BigInteger([1, 2, 3, 4], 256).toString(16) != '1020304') return false;
|
||||
if (new BigInteger([1, 2, 3, 4, 5], 256).toString(16) != '102030405') return false;
|
||||
if (new BigInteger([1, 2, 3, 4, 5, 6, 7, 8], 256).toString(16) != '102030405060708') return false;
|
||||
if (new BigInteger([1, 2, 3, 4], 256).toByteArray().join(',') != '1,2,3,4') return false;
|
||||
if (new BigInteger([1, 2, 3, 4, 5, 6, 7, 8], 256).toByteArray().join(',') != '1,2,3,4,5,6,7,8') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldReturnProperBitLength: function () {
|
||||
if (new BigInteger('0').bitLength() != 0) return false;
|
||||
if (new BigInteger('1', 16).bitLength() != 1) return false;
|
||||
if (new BigInteger('2', 16).bitLength() != 2) return false;
|
||||
if (new BigInteger('3', 16).bitLength() != 2) return false;
|
||||
if (new BigInteger('4', 16).bitLength() != 3) return false;
|
||||
if (new BigInteger('8', 16).bitLength() != 4) return false;
|
||||
if (new BigInteger('10', 16).bitLength() != 5) return false;
|
||||
if (new BigInteger('100', 16).bitLength() != 9) return false;
|
||||
if (new BigInteger('123456', 16).bitLength() != 21) return false;
|
||||
if (new BigInteger('123456789', 16).bitLength() != 33) return false;
|
||||
if (new BigInteger('8023456789', 16).bitLength() != 40) return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldAddNumbers: function () {
|
||||
// test 1
|
||||
if (new BigInteger('14').add(new BigInteger('26')).toString(16) != '28') return false;
|
||||
|
||||
// test 2
|
||||
var k = new BigInteger('1234', 16);
|
||||
var r = k;
|
||||
for (var i = 0; i < 257; i++) r = r.add(k);
|
||||
if (r.toString(16) != '125868') return false;
|
||||
|
||||
// test 3
|
||||
var k = new BigInteger('abcdefabcdefabcdef', 16);
|
||||
var r = new BigInteger('deadbeef', 16);
|
||||
for (var i = 0; i < 257; i++) {
|
||||
r = r.add(k);
|
||||
}
|
||||
if (r.toString(16) != 'ac79bd9b79be7a277bde') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldSubtractNumbers: function () {
|
||||
// test 1
|
||||
if (new BigInteger('14').subtract(new BigInteger('26')).toString(16) != '-c') return false;
|
||||
// test 2
|
||||
if (new BigInteger('26').subtract(new BigInteger('14')).toString(16) != 'c') return false;
|
||||
// test 3
|
||||
if (new BigInteger('26').subtract(new BigInteger('26')).toString(16) != '0') return false;
|
||||
// test 4
|
||||
if (new BigInteger('-26').subtract(new BigInteger('26')).toString(16) != '-34') return false;
|
||||
// test 5
|
||||
var a = new BigInteger('31ff3c61db2db84b9823d320907a573f6ad37c437abe458b1802cda041d6384a7d8daef41395491e2', 16);
|
||||
var b = new BigInteger('6f0e4d9f1d6071c183677f601af9305721c91d31b0bbbae8fb790000', 16);
|
||||
var r = new BigInteger('31ff3c61db2db84b9823d3208989726578fd75276287cd9516533a9acfb9a6776281f34583ddb91e2', 16);
|
||||
if (a.subtract(b).compareTo(r) != 0) return false;
|
||||
// test 6
|
||||
var r = b.subtract(new BigInteger('14'));
|
||||
if (b.clone().subtract(new BigInteger('14')).compareTo(r) != 0) return false;
|
||||
// test 7
|
||||
var r = new BigInteger('7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b', 16);
|
||||
if (r.subtract(new BigInteger('-1')).toString(16) != '7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681c') return false;
|
||||
// test 8
|
||||
// Carry and copy
|
||||
var a = new BigInteger('12345', 16);
|
||||
var b = new BigInteger('1000000000000', 16);
|
||||
if (a.subtract(b).toString(16) != '-fffffffedcbb') return false;
|
||||
// test 9
|
||||
var a = new BigInteger('12345', 16);
|
||||
var b = new BigInteger('1000000000000', 16);
|
||||
if (b.subtract(a).toString(16) != 'fffffffedcbb') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldMultiplyNumbers: function () {
|
||||
if (new BigInteger('1001', 16).multiply(new BigInteger('1234', 16)).toString(16) != '1235234') return false;
|
||||
if (new BigInteger('-1001', 16).multiply(new BigInteger('1234', 16)).toString(16) != '-1235234') return false;
|
||||
if (new BigInteger('-1001', 16).multiply(new BigInteger('-1234', 16)).toString(16) != '1235234') return false;
|
||||
|
||||
// test 4
|
||||
var n = new BigInteger('1001', 16);
|
||||
var r = n;
|
||||
for (var i = 0; i < 4; i++) {
|
||||
r = r.multiply(n);
|
||||
}
|
||||
if (r.toString(16) != '100500a00a005001') return false;
|
||||
|
||||
var n = new BigInteger('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16);
|
||||
if (n.multiply(n).toString(16) != '39e58a8055b6fb264b75ec8c646509784204ac15a8c24e05babc9729ab9b055c3a9458e4ce3289560a38e08ba8175a9446ce14e608245ab3a9978a8bd8acaa40') return false;
|
||||
if (n.multiply(n).multiply(n).toString(16) != '1b888e01a06e974017a28a5b4da436169761c9730b7aeedf75fc60f687b46e0cf2cb11667f795d5569482640fe5f628939467a01a612b023500d0161e9730279a7561043af6197798e41b7432458463e64fa81158907322dc330562697d0d600') return false;
|
||||
|
||||
if (new BigInteger('-100000000000').multiply(new BigInteger('3').divide(new BigInteger('4'))).toString(16) != '0') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldDivideNumbers: function () {
|
||||
if (new BigInteger('10').divide(new BigInteger('256')).toString(16) != '0') return false;
|
||||
if (new BigInteger('69527932928').divide(new BigInteger('16974594')).toString(16) != 'fff') return false;
|
||||
if (new BigInteger('-69527932928').divide(new BigInteger('16974594')).toString(16) != '-fff') return false;
|
||||
|
||||
var b = new BigInteger('39e58a8055b6fb264b75ec8c646509784204ac15a8c24e05babc9729ab9b055c3a9458e4ce3289560a38e08ba8175a9446ce14e608245ab3a9978a8bd8acaa40', 16);
|
||||
var n = new BigInteger('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16);
|
||||
if (b.divide(n).toString(16) != n.toString(16)) return false;
|
||||
|
||||
if (new BigInteger('1').divide(new BigInteger('-5')).toString(10) != '0') return false;
|
||||
|
||||
// // Regression after moving to word div
|
||||
var p = new BigInteger('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16);
|
||||
var a = new BigInteger('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16);
|
||||
var as = a.square();
|
||||
if (as.divide(p).toString(16) != '39e58a8055b6fb264b75ec8c646509784204ac15a8c24e05babc9729e58090b9') return false;
|
||||
|
||||
var p = new BigInteger('ffffffff00000001000000000000000000000000ffffffffffffffffffffffff', 16);
|
||||
var a = new BigInteger('fffffffe00000003fffffffd0000000200000001fffffffe00000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16);
|
||||
if (a.divide(p).toString(16) != 'ffffffff00000002000000000000000000000001000000000000000000000001') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldModNumbers: function () {
|
||||
if (new BigInteger('10').mod(new BigInteger('256')).toString(16) != 'a') return false;
|
||||
if (new BigInteger('69527932928').mod(new BigInteger('16974594')).toString(16) != '102f302') return false;
|
||||
if (new BigInteger('-69527932928').mod(new BigInteger('16974594')).toString(16) != '1000') return false;
|
||||
if (new BigInteger('10', 16).mod(new BigInteger('256')).toString(16) != '10') return false;
|
||||
if (new BigInteger('100', 16).mod(new BigInteger('256')).toString(16) != '0') return false;
|
||||
if (new BigInteger('1001', 16).mod(new BigInteger('256')).toString(16) != '1') return false;
|
||||
if (new BigInteger('100000000001', 16).mod(new BigInteger('256')).toString(16) != '1') return false;
|
||||
if (new BigInteger('100000000001', 16).mod(new BigInteger('257')).toString(16) != new BigInteger('100000000001', 16).mod(new BigInteger('257')).toString(16)) return false;
|
||||
if (new BigInteger('123456789012', 16).mod(new BigInteger('3')).toString(16) != new BigInteger('123456789012', 16).mod(new BigInteger('3')).toString(16)) return false;
|
||||
|
||||
var p = new BigInteger('ffffffff00000001000000000000000000000000ffffffffffffffffffffffff', 16);
|
||||
var a = new BigInteger('fffffffe00000003fffffffd0000000200000001fffffffe00000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16);
|
||||
if (a.mod(p).toString(16) != '0') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldShiftLeftNumbers: function () {
|
||||
if (new BigInteger('69527932928').shiftLeft(13).toString(16) != '2060602000000') return false;
|
||||
if (new BigInteger('69527932928').shiftLeft(45).toString(16) != '206060200000000000000') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldShiftRightNumbers: function () {
|
||||
if (new BigInteger('69527932928').shiftRight(13).toString(16) != '818180') return false;
|
||||
if (new BigInteger('69527932928').shiftRight(17).toString(16) != '81818') return false;
|
||||
if (new BigInteger('69527932928').shiftRight(256).toString(16) != '0') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldModInverseNumbers: function () {
|
||||
var p = new BigInteger('257');
|
||||
var a = new BigInteger('3');
|
||||
var b = a.modInverse(p);
|
||||
if (a.multiply(b).mod(p).toString(16) != '1') return false;
|
||||
|
||||
var p192 = new BigInteger('fffffffffffffffffffffffffffffffeffffffffffffffff', 16);
|
||||
var a = new BigInteger('deadbeef', 16);
|
||||
var b = a.modInverse(p192);
|
||||
if (a.multiply(b).mod(p192).toString(16) != '1') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldThrowOnModInverseOfZero: function () {
|
||||
var p = new BigInteger('257');
|
||||
var a = new BigInteger('0');
|
||||
//division by zero
|
||||
try {
|
||||
a.modInverse(p);
|
||||
}
|
||||
catch (e) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
testBigIntegerShouldAlwaysReturnPositiveNumber: function () {
|
||||
var z = new BigInteger('cc61934972bba029382f0bef146b228ca15d54f7e38b6cd5f6b382398b7a97a8', 16);
|
||||
var p = new BigInteger('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16);
|
||||
var zInv = z.modInverse(p);
|
||||
if (zInv.signum() !== 1) return false; //zInv should be positive
|
||||
|
||||
return true;
|
||||
},
|
||||
testECKeyDoesntHangWithSpecificKey: function () {
|
||||
var key = "848b39bbe4c9ddf978d3d8f786315bdc3ba71237d5f780399e0026e1269313ef";
|
||||
var btcKey = new Bitcoin.ECKey(key);
|
||||
if (btcKey.getPubKeyHex() != "0478BC8F7CB4485E7A0314A698AA1600639FF2922D09C26DED5F730CAC4784477D2B325922459F017AC1E8775436D11D7F84BD84E11CB64FC9BE110931D0C990CE"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
asynchronousTests: {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "bitaddress.org",
|
||||
"version": "3.2.0",
|
||||
"sha1sum": "057f3192b603d42c980ea23d5ae332a65f7a327c",
|
||||
"sha256sum": "ad4fd171c647772aa76d0ce828731b01ca586596275d43a94008766b758e8736",
|
||||
"version": "3.2.1",
|
||||
"sha1sum": "",
|
||||
"sha256sum": "",
|
||||
"description": "Open Source JavaScript Client-Side Bitcoin Wallet Generator",
|
||||
"main": "Gruntfile.js",
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
// Upstream 'BigInteger' here:
|
||||
// Original Author: http://www-cs-students.stanford.edu/~tjw/jsbn/
|
||||
// Follows 'jsbn' on Github: https://github.com/jasondavies/jsbn
|
||||
// Review and Testing: https://github.com/cryptocoinjs/bigi/
|
||||
/*!
|
||||
* Basic JavaScript BN library - subset useful for RSA encryption. v1.3
|
||||
* Basic JavaScript BN library - subset useful for RSA encryption. v1.4
|
||||
*
|
||||
* Copyright (c) 2005 Tom Wu
|
||||
* All Rights Reserved.
|
||||
|
@ -7,13 +11,16 @@
|
|||
* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
|
||||
*
|
||||
* Copyright Stephan Thomas
|
||||
* Copyright bitaddress.org
|
||||
* Copyright pointbiz
|
||||
*/
|
||||
|
||||
(function () {
|
||||
|
||||
// (public) Constructor function of Global BigInteger object
|
||||
var BigInteger = window.BigInteger = function BigInteger(a, b, c) {
|
||||
if (!(this instanceof BigInteger))
|
||||
return new BigInteger(a, b, c);
|
||||
|
||||
if (a != null)
|
||||
if ("number" == typeof a) this.fromNumber(a, b, c);
|
||||
else if (b == null && "string" != typeof a) this.fromString(a, 256);
|
||||
|
@ -944,6 +951,7 @@
|
|||
// (public) 1/this % m (HAC 14.61)
|
||||
BigInteger.prototype.modInverse = function (m) {
|
||||
var ac = m.isEven();
|
||||
if (this.signum() === 0) throw new Error('division by zero');
|
||||
if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
|
||||
var u = m.clone(), v = this.clone();
|
||||
var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
|
||||
|
@ -978,9 +986,9 @@
|
|||
}
|
||||
}
|
||||
if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
|
||||
if (d.compareTo(m) >= 0) return d.subtract(m);
|
||||
if (d.signum() < 0) d.addTo(m, d); else return d;
|
||||
if (d.signum() < 0) return d.add(m); else return d;
|
||||
while (d.compareTo(m) >= 0) d.subTo(m, d);
|
||||
while (d.signum() < 0) d.addTo(m, d);
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
}
|
||||
testResults += passCount + " of " + testCount + " synchronous tests passed";
|
||||
if (passCount < testCount) {
|
||||
testResults += "<b>" + (testCount - passCount) + " unit test(s) failed</b>";
|
||||
testResults += "<br/><b>" + (testCount - passCount) + " unit test(s) failed</b>";
|
||||
}
|
||||
if (showOutput) {
|
||||
div.innerHTML = "<h3>Unit Tests</h3><div id=\"unittestresults\">" + testResults + "<br/><br/></div>";
|
||||
|
@ -621,7 +621,223 @@
|
|||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
//BigInteger tests
|
||||
testBigIntegerShouldWorkWithoutNew: function () {
|
||||
var bi = BigInteger('12345')
|
||||
if (bi.toString(10) != '12345') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldWorkWithStringInput: function () {
|
||||
if (new BigInteger('12345').toString(16) != '3039') return false;
|
||||
if (new BigInteger('29048849665247').toString(16) != '1a6b765d8cdf') return false;
|
||||
if (new BigInteger('-29048849665247').toString(16) != '-1a6b765d8cdf') return false;
|
||||
if (new BigInteger('1A6B765D8CDF', 16).toString(16) != '1a6b765d8cdf') return false;
|
||||
if (new BigInteger('FF', 16).toString() != '255') return false;
|
||||
if (new BigInteger('1A6B765D8CDF', 16).toString() != '29048849665247') return false;
|
||||
if (new BigInteger('a89c e5af8724 c0a23e0e 0ff77500', 16).toString(16) != 'a89ce5af8724c0a23e0e0ff77500') return false;
|
||||
if (new BigInteger('123456789abcdef123456789abcdef123456789abcdef', 16).toString(16) != '123456789abcdef123456789abcdef123456789abcdef') return false;
|
||||
if (new BigInteger('10654321').toString() != '10654321') return false;
|
||||
if (new BigInteger('10000000000000000').toString(10) != '10000000000000000') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldImportExportTwosComplementBigEndian: function () {
|
||||
if (new BigInteger([1, 2, 3], 256).toString(16) != '10203') return false;
|
||||
if (new BigInteger([1, 2, 3, 4], 256).toString(16) != '1020304') return false;
|
||||
if (new BigInteger([1, 2, 3, 4, 5], 256).toString(16) != '102030405') return false;
|
||||
if (new BigInteger([1, 2, 3, 4, 5, 6, 7, 8], 256).toString(16) != '102030405060708') return false;
|
||||
if (new BigInteger([1, 2, 3, 4], 256).toByteArray().join(',') != '1,2,3,4') return false;
|
||||
if (new BigInteger([1, 2, 3, 4, 5, 6, 7, 8], 256).toByteArray().join(',') != '1,2,3,4,5,6,7,8') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldReturnProperBitLength: function () {
|
||||
if (new BigInteger('0').bitLength() != 0) return false;
|
||||
if (new BigInteger('1', 16).bitLength() != 1) return false;
|
||||
if (new BigInteger('2', 16).bitLength() != 2) return false;
|
||||
if (new BigInteger('3', 16).bitLength() != 2) return false;
|
||||
if (new BigInteger('4', 16).bitLength() != 3) return false;
|
||||
if (new BigInteger('8', 16).bitLength() != 4) return false;
|
||||
if (new BigInteger('10', 16).bitLength() != 5) return false;
|
||||
if (new BigInteger('100', 16).bitLength() != 9) return false;
|
||||
if (new BigInteger('123456', 16).bitLength() != 21) return false;
|
||||
if (new BigInteger('123456789', 16).bitLength() != 33) return false;
|
||||
if (new BigInteger('8023456789', 16).bitLength() != 40) return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldAddNumbers: function () {
|
||||
// test 1
|
||||
if (new BigInteger('14').add(new BigInteger('26')).toString(16) != '28') return false;
|
||||
|
||||
// test 2
|
||||
var k = new BigInteger('1234', 16);
|
||||
var r = k;
|
||||
for (var i = 0; i < 257; i++) r = r.add(k);
|
||||
if (r.toString(16) != '125868') return false;
|
||||
|
||||
// test 3
|
||||
var k = new BigInteger('abcdefabcdefabcdef', 16);
|
||||
var r = new BigInteger('deadbeef', 16);
|
||||
for (var i = 0; i < 257; i++) {
|
||||
r = r.add(k);
|
||||
}
|
||||
if (r.toString(16) != 'ac79bd9b79be7a277bde') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldSubtractNumbers: function () {
|
||||
// test 1
|
||||
if (new BigInteger('14').subtract(new BigInteger('26')).toString(16) != '-c') return false;
|
||||
// test 2
|
||||
if (new BigInteger('26').subtract(new BigInteger('14')).toString(16) != 'c') return false;
|
||||
// test 3
|
||||
if (new BigInteger('26').subtract(new BigInteger('26')).toString(16) != '0') return false;
|
||||
// test 4
|
||||
if (new BigInteger('-26').subtract(new BigInteger('26')).toString(16) != '-34') return false;
|
||||
// test 5
|
||||
var a = new BigInteger('31ff3c61db2db84b9823d320907a573f6ad37c437abe458b1802cda041d6384a7d8daef41395491e2', 16);
|
||||
var b = new BigInteger('6f0e4d9f1d6071c183677f601af9305721c91d31b0bbbae8fb790000', 16);
|
||||
var r = new BigInteger('31ff3c61db2db84b9823d3208989726578fd75276287cd9516533a9acfb9a6776281f34583ddb91e2', 16);
|
||||
if (a.subtract(b).compareTo(r) != 0) return false;
|
||||
// test 6
|
||||
var r = b.subtract(new BigInteger('14'));
|
||||
if (b.clone().subtract(new BigInteger('14')).compareTo(r) != 0) return false;
|
||||
// test 7
|
||||
var r = new BigInteger('7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b', 16);
|
||||
if (r.subtract(new BigInteger('-1')).toString(16) != '7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681c') return false;
|
||||
// test 8
|
||||
// Carry and copy
|
||||
var a = new BigInteger('12345', 16);
|
||||
var b = new BigInteger('1000000000000', 16);
|
||||
if (a.subtract(b).toString(16) != '-fffffffedcbb') return false;
|
||||
// test 9
|
||||
var a = new BigInteger('12345', 16);
|
||||
var b = new BigInteger('1000000000000', 16);
|
||||
if (b.subtract(a).toString(16) != 'fffffffedcbb') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldMultiplyNumbers: function () {
|
||||
if (new BigInteger('1001', 16).multiply(new BigInteger('1234', 16)).toString(16) != '1235234') return false;
|
||||
if (new BigInteger('-1001', 16).multiply(new BigInteger('1234', 16)).toString(16) != '-1235234') return false;
|
||||
if (new BigInteger('-1001', 16).multiply(new BigInteger('-1234', 16)).toString(16) != '1235234') return false;
|
||||
|
||||
// test 4
|
||||
var n = new BigInteger('1001', 16);
|
||||
var r = n;
|
||||
for (var i = 0; i < 4; i++) {
|
||||
r = r.multiply(n);
|
||||
}
|
||||
if (r.toString(16) != '100500a00a005001') return false;
|
||||
|
||||
var n = new BigInteger('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16);
|
||||
if (n.multiply(n).toString(16) != '39e58a8055b6fb264b75ec8c646509784204ac15a8c24e05babc9729ab9b055c3a9458e4ce3289560a38e08ba8175a9446ce14e608245ab3a9978a8bd8acaa40') return false;
|
||||
if (n.multiply(n).multiply(n).toString(16) != '1b888e01a06e974017a28a5b4da436169761c9730b7aeedf75fc60f687b46e0cf2cb11667f795d5569482640fe5f628939467a01a612b023500d0161e9730279a7561043af6197798e41b7432458463e64fa81158907322dc330562697d0d600') return false;
|
||||
|
||||
if (new BigInteger('-100000000000').multiply(new BigInteger('3').divide(new BigInteger('4'))).toString(16) != '0') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldDivideNumbers: function () {
|
||||
if (new BigInteger('10').divide(new BigInteger('256')).toString(16) != '0') return false;
|
||||
if (new BigInteger('69527932928').divide(new BigInteger('16974594')).toString(16) != 'fff') return false;
|
||||
if (new BigInteger('-69527932928').divide(new BigInteger('16974594')).toString(16) != '-fff') return false;
|
||||
|
||||
var b = new BigInteger('39e58a8055b6fb264b75ec8c646509784204ac15a8c24e05babc9729ab9b055c3a9458e4ce3289560a38e08ba8175a9446ce14e608245ab3a9978a8bd8acaa40', 16);
|
||||
var n = new BigInteger('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16);
|
||||
if (b.divide(n).toString(16) != n.toString(16)) return false;
|
||||
|
||||
if (new BigInteger('1').divide(new BigInteger('-5')).toString(10) != '0') return false;
|
||||
|
||||
// // Regression after moving to word div
|
||||
var p = new BigInteger('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16);
|
||||
var a = new BigInteger('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16);
|
||||
var as = a.square();
|
||||
if (as.divide(p).toString(16) != '39e58a8055b6fb264b75ec8c646509784204ac15a8c24e05babc9729e58090b9') return false;
|
||||
|
||||
var p = new BigInteger('ffffffff00000001000000000000000000000000ffffffffffffffffffffffff', 16);
|
||||
var a = new BigInteger('fffffffe00000003fffffffd0000000200000001fffffffe00000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16);
|
||||
if (a.divide(p).toString(16) != 'ffffffff00000002000000000000000000000001000000000000000000000001') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldModNumbers: function () {
|
||||
if (new BigInteger('10').mod(new BigInteger('256')).toString(16) != 'a') return false;
|
||||
if (new BigInteger('69527932928').mod(new BigInteger('16974594')).toString(16) != '102f302') return false;
|
||||
if (new BigInteger('-69527932928').mod(new BigInteger('16974594')).toString(16) != '1000') return false;
|
||||
if (new BigInteger('10', 16).mod(new BigInteger('256')).toString(16) != '10') return false;
|
||||
if (new BigInteger('100', 16).mod(new BigInteger('256')).toString(16) != '0') return false;
|
||||
if (new BigInteger('1001', 16).mod(new BigInteger('256')).toString(16) != '1') return false;
|
||||
if (new BigInteger('100000000001', 16).mod(new BigInteger('256')).toString(16) != '1') return false;
|
||||
if (new BigInteger('100000000001', 16).mod(new BigInteger('257')).toString(16) != new BigInteger('100000000001', 16).mod(new BigInteger('257')).toString(16)) return false;
|
||||
if (new BigInteger('123456789012', 16).mod(new BigInteger('3')).toString(16) != new BigInteger('123456789012', 16).mod(new BigInteger('3')).toString(16)) return false;
|
||||
|
||||
var p = new BigInteger('ffffffff00000001000000000000000000000000ffffffffffffffffffffffff', 16);
|
||||
var a = new BigInteger('fffffffe00000003fffffffd0000000200000001fffffffe00000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16);
|
||||
if (a.mod(p).toString(16) != '0') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldShiftLeftNumbers: function () {
|
||||
if (new BigInteger('69527932928').shiftLeft(13).toString(16) != '2060602000000') return false;
|
||||
if (new BigInteger('69527932928').shiftLeft(45).toString(16) != '206060200000000000000') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldShiftRightNumbers: function () {
|
||||
if (new BigInteger('69527932928').shiftRight(13).toString(16) != '818180') return false;
|
||||
if (new BigInteger('69527932928').shiftRight(17).toString(16) != '81818') return false;
|
||||
if (new BigInteger('69527932928').shiftRight(256).toString(16) != '0') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldModInverseNumbers: function () {
|
||||
var p = new BigInteger('257');
|
||||
var a = new BigInteger('3');
|
||||
var b = a.modInverse(p);
|
||||
if (a.multiply(b).mod(p).toString(16) != '1') return false;
|
||||
|
||||
var p192 = new BigInteger('fffffffffffffffffffffffffffffffeffffffffffffffff', 16);
|
||||
var a = new BigInteger('deadbeef', 16);
|
||||
var b = a.modInverse(p192);
|
||||
if (a.multiply(b).mod(p192).toString(16) != '1') return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
testBigIntegerShouldThrowOnModInverseOfZero: function () {
|
||||
var p = new BigInteger('257');
|
||||
var a = new BigInteger('0');
|
||||
//division by zero
|
||||
try {
|
||||
a.modInverse(p);
|
||||
}
|
||||
catch (e) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
testBigIntegerShouldAlwaysReturnPositiveNumber: function () {
|
||||
var z = new BigInteger('cc61934972bba029382f0bef146b228ca15d54f7e38b6cd5f6b382398b7a97a8', 16);
|
||||
var p = new BigInteger('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16);
|
||||
var zInv = z.modInverse(p);
|
||||
if (zInv.signum() !== 1) return false; //zInv should be positive
|
||||
|
||||
return true;
|
||||
},
|
||||
testECKeyDoesntHangWithSpecificKey: function () {
|
||||
var key = "848b39bbe4c9ddf978d3d8f786315bdc3ba71237d5f780399e0026e1269313ef";
|
||||
var btcKey = new Bitcoin.ECKey(key);
|
||||
if (btcKey.getPubKeyHex() != "0478BC8F7CB4485E7A0314A698AA1600639FF2922D09C26DED5F730CAC4784477D2B325922459F017AC1E8775436D11D7F84BD84E11CB64FC9BE110931D0C990CE"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
asynchronousTests: {
|
||||
|
|
Loading…
Reference in a new issue