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.

190 lines
5.2 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. /*
  2. Copyright 2018 0kims association.
  3. This file is part of snarkjs.
  4. snarkjs is a free software: you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License as published by the
  6. Free Software Foundation, either version 3 of the License, or (at your option)
  7. any later version.
  8. snarkjs is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. more details.
  12. You should have received a copy of the GNU General Public License along with
  13. snarkjs. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. const fUtils = require("./futils.js");
  16. class GCurve {
  17. constructor(F, g) {
  18. this.F = F;
  19. this.g = [F.copy(g[0]), F.copy(g[1])];
  20. if (this.g.length == 2) this.g[2] = this.F.one;
  21. this.zero = [this.F.zero, this.F.one, this.F.zero];
  22. }
  23. isZero(p) {
  24. return this.F.isZero(p[2]);
  25. }
  26. add(p1, p2) {
  27. const F = this.F;
  28. if (this.isZero(p1)) return p2;
  29. if (this.isZero(p2)) return p1;
  30. const res = new Array(3);
  31. const Z1Z1 = F.square( p1[2] );
  32. const Z2Z2 = F.square( p2[2] );
  33. const U1 = F.mul( p1[0] , Z2Z2 ); // U1 = X1 * Z2Z2
  34. const U2 = F.mul( p2[0] , Z1Z1 ); // U2 = X2 * Z1Z1
  35. const Z1_cubed = F.mul( p1[2] , Z1Z1);
  36. const Z2_cubed = F.mul( p2[2] , Z2Z2);
  37. const S1 = F.mul( p1[1] , Z2_cubed); // S1 = Y1 * Z2 * Z2Z2
  38. const S2 = F.mul( p2[1] , Z1_cubed); // S2 = Y2 * Z1 * Z1Z1
  39. if (F.equals(U1,U2) && F.equals(S1,S2)) {
  40. return this.double(p1);
  41. }
  42. const H = F.sub( U2 , U1 ); // H = U2-U1
  43. const S2_minus_S1 = F.sub( S2 , S1 );
  44. const I = F.square( F.add(H,H) ); // I = (2 * H)^2
  45. const J = F.mul( H , I ); // J = H * I
  46. const r = F.add( S2_minus_S1 , S2_minus_S1 ); // r = 2 * (S2-S1)
  47. const V = F.mul( U1 , I ); // V = U1 * I
  48. res[0] =
  49. F.sub(
  50. F.sub( F.square(r) , J ),
  51. F.add( V , V )); // X3 = r^2 - J - 2 * V
  52. const S1_J = F.mul( S1 , J );
  53. res[1] =
  54. F.sub(
  55. F.mul( r , F.sub(V,res[0])),
  56. F.add( S1_J,S1_J )); // Y3 = r * (V-X3)-2 S1 J
  57. res[2] =
  58. F.mul(
  59. H,
  60. F.sub(
  61. F.square( F.add(p1[2],p2[2]) ),
  62. F.add( Z1Z1 , Z2Z2 ))); // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
  63. return res;
  64. }
  65. neg(p) {
  66. return [p[0], this.F.neg(p[1]), p[2]];
  67. }
  68. sub(a, b) {
  69. return this.add(a, this.neg(b));
  70. }
  71. double(p) {
  72. const F = this.F;
  73. const res = new Array(3);
  74. if (this.isZero(p)) return p;
  75. const A = F.square( p[0] ); // A = X1^2
  76. const B = F.square( p[1] ); // B = Y1^2
  77. const C = F.square( B ); // C = B^2
  78. let D =
  79. F.sub(
  80. F.square( F.add(p[0] , B )),
  81. F.add( A , C));
  82. D = F.add(D,D); // D = 2 * ((X1 + B)^2 - A - C)
  83. const E = F.add( F.add(A,A), A); // E = 3 * A
  84. const FF =F.square( E ); // F = E^2
  85. res[0] = F.sub( FF , F.add(D,D) ); // X3 = F - 2 D
  86. let eightC = F.add( C , C );
  87. eightC = F.add( eightC , eightC );
  88. eightC = F.add( eightC , eightC );
  89. res[1] =
  90. F.sub(
  91. F.mul(
  92. E,
  93. F.sub( D, res[0] )),
  94. eightC); // Y3 = E * (D - X3) - 8 * C
  95. const Y1Z1 = F.mul( p[1] , p[2] );
  96. res[2] = F.add( Y1Z1 , Y1Z1 ); // Z3 = 2 * Y1 * Z1
  97. return res;
  98. }
  99. mulScalar(base, e) {
  100. return fUtils.mulScalar(this, base, e);
  101. }
  102. affine(p) {
  103. const F = this.F;
  104. if (this.isZero(p)) {
  105. return this.zero;
  106. } else {
  107. const Z_inv = F.inverse(p[2]);
  108. const Z2_inv = F.square(Z_inv);
  109. const Z3_inv = F.mul(Z2_inv, Z_inv);
  110. const res = new Array(3);
  111. res[0] = F.affine( F.mul(p[0],Z2_inv));
  112. res[1] = F.affine( F.mul(p[1],Z3_inv));
  113. res[2] = F.one;
  114. return res;
  115. }
  116. }
  117. equals(p1, p2) {
  118. const F = this.F;
  119. if (this.isZero(p1)) return this.isZero(p2);
  120. if (this.isZero(p2)) return this.isZero(p1);
  121. const Z1Z1 = F.square( p1[2] );
  122. const Z2Z2 = F.square( p2[2] );
  123. const U1 = F.mul( p1[0] , Z2Z2 );
  124. const U2 = F.mul( p2[0] , Z1Z1 );
  125. const Z1_cubed = F.mul( p1[2] , Z1Z1);
  126. const Z2_cubed = F.mul( p2[2] , Z2Z2);
  127. const S1 = F.mul( p1[1] , Z2_cubed);
  128. const S2 = F.mul( p2[1] , Z1_cubed);
  129. return (F.equals(U1,U2) && F.equals(S1,S2));
  130. }
  131. toString(p) {
  132. const cp = this.affine(p);
  133. return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])} ]`;
  134. }
  135. }
  136. module.exports = GCurve;