mont.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. 'use strict';
  2. var BN = require('bn.js');
  3. var inherits = require('inherits');
  4. var Base = require('./base');
  5. var utils = require('../utils');
  6. function MontCurve(conf) {
  7. Base.call(this, 'mont', conf);
  8. this.a = new BN(conf.a, 16).toRed(this.red);
  9. this.b = new BN(conf.b, 16).toRed(this.red);
  10. this.i4 = new BN(4).toRed(this.red).redInvm();
  11. this.two = new BN(2).toRed(this.red);
  12. this.a24 = this.i4.redMul(this.a.redAdd(this.two));
  13. }
  14. inherits(MontCurve, Base);
  15. module.exports = MontCurve;
  16. MontCurve.prototype.validate = function validate(point) {
  17. var x = point.normalize().x;
  18. var x2 = x.redSqr();
  19. var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x);
  20. var y = rhs.redSqrt();
  21. return y.redSqr().cmp(rhs) === 0;
  22. };
  23. function Point(curve, x, z) {
  24. Base.BasePoint.call(this, curve, 'projective');
  25. if (x === null && z === null) {
  26. this.x = this.curve.one;
  27. this.z = this.curve.zero;
  28. } else {
  29. this.x = new BN(x, 16);
  30. this.z = new BN(z, 16);
  31. if (!this.x.red)
  32. this.x = this.x.toRed(this.curve.red);
  33. if (!this.z.red)
  34. this.z = this.z.toRed(this.curve.red);
  35. }
  36. }
  37. inherits(Point, Base.BasePoint);
  38. MontCurve.prototype.decodePoint = function decodePoint(bytes, enc) {
  39. return this.point(utils.toArray(bytes, enc), 1);
  40. };
  41. MontCurve.prototype.point = function point(x, z) {
  42. return new Point(this, x, z);
  43. };
  44. MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) {
  45. return Point.fromJSON(this, obj);
  46. };
  47. Point.prototype.precompute = function precompute() {
  48. // No-op
  49. };
  50. Point.prototype._encode = function _encode() {
  51. return this.getX().toArray('be', this.curve.p.byteLength());
  52. };
  53. Point.fromJSON = function fromJSON(curve, obj) {
  54. return new Point(curve, obj[0], obj[1] || curve.one);
  55. };
  56. Point.prototype.inspect = function inspect() {
  57. if (this.isInfinity())
  58. return '<EC Point Infinity>';
  59. return '<EC Point x: ' + this.x.fromRed().toString(16, 2) +
  60. ' z: ' + this.z.fromRed().toString(16, 2) + '>';
  61. };
  62. Point.prototype.isInfinity = function isInfinity() {
  63. // XXX This code assumes that zero is always zero in red
  64. return this.z.cmpn(0) === 0;
  65. };
  66. Point.prototype.dbl = function dbl() {
  67. // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3
  68. // 2M + 2S + 4A
  69. // A = X1 + Z1
  70. var a = this.x.redAdd(this.z);
  71. // AA = A^2
  72. var aa = a.redSqr();
  73. // B = X1 - Z1
  74. var b = this.x.redSub(this.z);
  75. // BB = B^2
  76. var bb = b.redSqr();
  77. // C = AA - BB
  78. var c = aa.redSub(bb);
  79. // X3 = AA * BB
  80. var nx = aa.redMul(bb);
  81. // Z3 = C * (BB + A24 * C)
  82. var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c)));
  83. return this.curve.point(nx, nz);
  84. };
  85. Point.prototype.add = function add() {
  86. throw new Error('Not supported on Montgomery curve');
  87. };
  88. Point.prototype.diffAdd = function diffAdd(p, diff) {
  89. // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3
  90. // 4M + 2S + 6A
  91. // A = X2 + Z2
  92. var a = this.x.redAdd(this.z);
  93. // B = X2 - Z2
  94. var b = this.x.redSub(this.z);
  95. // C = X3 + Z3
  96. var c = p.x.redAdd(p.z);
  97. // D = X3 - Z3
  98. var d = p.x.redSub(p.z);
  99. // DA = D * A
  100. var da = d.redMul(a);
  101. // CB = C * B
  102. var cb = c.redMul(b);
  103. // X5 = Z1 * (DA + CB)^2
  104. var nx = diff.z.redMul(da.redAdd(cb).redSqr());
  105. // Z5 = X1 * (DA - CB)^2
  106. var nz = diff.x.redMul(da.redISub(cb).redSqr());
  107. return this.curve.point(nx, nz);
  108. };
  109. Point.prototype.mul = function mul(k) {
  110. var t = k.clone();
  111. var a = this; // (N / 2) * Q + Q
  112. var b = this.curve.point(null, null); // (N / 2) * Q
  113. var c = this; // Q
  114. for (var bits = []; t.cmpn(0) !== 0; t.iushrn(1))
  115. bits.push(t.andln(1));
  116. for (var i = bits.length - 1; i >= 0; i--) {
  117. if (bits[i] === 0) {
  118. // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q
  119. a = a.diffAdd(b, c);
  120. // N * Q = 2 * ((N / 2) * Q + Q))
  121. b = b.dbl();
  122. } else {
  123. // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q)
  124. b = a.diffAdd(b, c);
  125. // N * Q + Q = 2 * ((N / 2) * Q + Q)
  126. a = a.dbl();
  127. }
  128. }
  129. return b;
  130. };
  131. Point.prototype.mulAdd = function mulAdd() {
  132. throw new Error('Not supported on Montgomery curve');
  133. };
  134. Point.prototype.jumlAdd = function jumlAdd() {
  135. throw new Error('Not supported on Montgomery curve');
  136. };
  137. Point.prototype.eq = function eq(other) {
  138. return this.getX().cmp(other.getX()) === 0;
  139. };
  140. Point.prototype.normalize = function normalize() {
  141. this.x = this.x.redMul(this.z.redInvm());
  142. this.z = this.curve.one;
  143. return this;
  144. };
  145. Point.prototype.getX = function getX() {
  146. // Normalize coordinates
  147. this.normalize();
  148. return this.x.fromRed();
  149. };