You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
2.4 KiB

4 years ago
  1. var bn = require('bn.js');
  2. var brorand = require('brorand');
  3. function MillerRabin(rand) {
  4. this.rand = rand || new brorand.Rand();
  5. }
  6. module.exports = MillerRabin;
  7. MillerRabin.create = function create(rand) {
  8. return new MillerRabin(rand);
  9. };
  10. MillerRabin.prototype._randbelow = function _randbelow(n) {
  11. var len = n.bitLength();
  12. var min_bytes = Math.ceil(len / 8);
  13. // Generage random bytes until a number less than n is found.
  14. // This ensures that 0..n-1 have an equal probability of being selected.
  15. do
  16. var a = new bn(this.rand.generate(min_bytes));
  17. while (a.cmp(n) >= 0);
  18. return a;
  19. };
  20. MillerRabin.prototype._randrange = function _randrange(start, stop) {
  21. // Generate a random number greater than or equal to start and less than stop.
  22. var size = stop.sub(start);
  23. return start.add(this._randbelow(size));
  24. };
  25. MillerRabin.prototype.test = function test(n, k, cb) {
  26. var len = n.bitLength();
  27. var red = bn.mont(n);
  28. var rone = new bn(1).toRed(red);
  29. if (!k)
  30. k = Math.max(1, (len / 48) | 0);
  31. // Find d and s, (n - 1) = (2 ^ s) * d;
  32. var n1 = n.subn(1);
  33. for (var s = 0; !n1.testn(s); s++) {}
  34. var d = n.shrn(s);
  35. var rn1 = n1.toRed(red);
  36. var prime = true;
  37. for (; k > 0; k--) {
  38. var a = this._randrange(new bn(2), n1);
  39. if (cb)
  40. cb(a);
  41. var x = a.toRed(red).redPow(d);
  42. if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)
  43. continue;
  44. for (var i = 1; i < s; i++) {
  45. x = x.redSqr();
  46. if (x.cmp(rone) === 0)
  47. return false;
  48. if (x.cmp(rn1) === 0)
  49. break;
  50. }
  51. if (i === s)
  52. return false;
  53. }
  54. return prime;
  55. };
  56. MillerRabin.prototype.getDivisor = function getDivisor(n, k) {
  57. var len = n.bitLength();
  58. var red = bn.mont(n);
  59. var rone = new bn(1).toRed(red);
  60. if (!k)
  61. k = Math.max(1, (len / 48) | 0);
  62. // Find d and s, (n - 1) = (2 ^ s) * d;
  63. var n1 = n.subn(1);
  64. for (var s = 0; !n1.testn(s); s++) {}
  65. var d = n.shrn(s);
  66. var rn1 = n1.toRed(red);
  67. for (; k > 0; k--) {
  68. var a = this._randrange(new bn(2), n1);
  69. var g = n.gcd(a);
  70. if (g.cmpn(1) !== 0)
  71. return g;
  72. var x = a.toRed(red).redPow(d);
  73. if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)
  74. continue;
  75. for (var i = 1; i < s; i++) {
  76. x = x.redSqr();
  77. if (x.cmp(rone) === 0)
  78. return x.fromRed().subn(1).gcd(n);
  79. if (x.cmp(rn1) === 0)
  80. break;
  81. }
  82. if (i === s) {
  83. x = x.redSqr();
  84. return x.fromRed().subn(1).gcd(n);
  85. }
  86. }
  87. return false;
  88. };