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.

177 lines
5.6 KiB

5 years ago
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 zksnark JavaScript library.
  4. zksnark JavaScript library 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. zksnark JavaScript library 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. zksnark JavaScript library. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. const fUtils = require("./futils.js");
  16. class F3Field {
  17. constructor(F, nonResidue) {
  18. this.F = F;
  19. this.zero = [this.F.zero, this.F.zero, this.F.zero];
  20. this.one = [this.F.one, this.F.zero, this.F.zero];
  21. this.nonResidue = nonResidue;
  22. }
  23. _mulByNonResidue(a) {
  24. return this.F.mul(this.nonResidue, a);
  25. }
  26. copy(a) {
  27. return [this.F.copy(a[0]), this.F.copy(a[1]), this.F.copy(a[2])];
  28. }
  29. add(a, b) {
  30. return [
  31. this.F.add(a[0], b[0]),
  32. this.F.add(a[1], b[1]),
  33. this.F.add(a[2], b[2])
  34. ];
  35. }
  36. double(a) {
  37. return this.add(a,a);
  38. }
  39. sub(a, b) {
  40. return [
  41. this.F.sub(a[0], b[0]),
  42. this.F.sub(a[1], b[1]),
  43. this.F.sub(a[2], b[2])
  44. ];
  45. }
  46. neg(a) {
  47. return this.sub(this.zero, a);
  48. }
  49. mul(a, b) {
  50. const aA = this.F.mul(a[0] , b[0]);
  51. const bB = this.F.mul(a[1] , b[1]);
  52. const cC = this.F.mul(a[2] , b[2]);
  53. return [
  54. this.F.add(
  55. aA,
  56. this._mulByNonResidue(
  57. this.F.sub(
  58. this.F.mul(
  59. this.F.add(a[1], a[2]),
  60. this.F.add(b[1], b[2])),
  61. this.F.add(bB, cC)))), // aA + non_residue*((b+c)*(B+C)-bB-cC),
  62. this.F.add(
  63. this.F.sub(
  64. this.F.mul(
  65. this.F.add(a[0], a[1]),
  66. this.F.add(b[0], b[1])),
  67. this.F.add(aA, bB)),
  68. this._mulByNonResidue( cC)), // (a+b)*(A+B)-aA-bB+non_residue*cC
  69. this.F.add(
  70. this.F.sub(
  71. this.F.mul(
  72. this.F.add(a[0], a[2]),
  73. this.F.add(b[0], b[2])),
  74. this.F.add(aA, cC)),
  75. bB)]; // (a+c)*(A+C)-aA+bB-cC)
  76. }
  77. inverse(a) {
  78. const t0 = this.F.square(a[0]); // t0 = a^2 ;
  79. const t1 = this.F.square(a[1]); // t1 = b^2 ;
  80. const t2 = this.F.square(a[2]); // t2 = c^2;
  81. const t3 = this.F.mul(a[0],a[1]); // t3 = ab
  82. const t4 = this.F.mul(a[0],a[2]); // t4 = ac
  83. const t5 = this.F.mul(a[1],a[2]); // t5 = bc;
  84. // c0 = t0 - non_residue * t5;
  85. const c0 = this.F.sub(t0, this._mulByNonResidue(t5));
  86. // c1 = non_residue * t2 - t3;
  87. const c1 = this.F.sub(this._mulByNonResidue(t2), t3);
  88. const c2 = this.F.sub(t1, t4); // c2 = t1-t4
  89. // t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inverse();
  90. const t6 =
  91. this.F.inverse(
  92. this.F.add(
  93. this.F.mul(a[0], c0),
  94. this._mulByNonResidue(
  95. this.F.add(
  96. this.F.mul(a[2], c1),
  97. this.F.mul(a[1], c2)))));
  98. return [
  99. this.F.mul(t6, c0), // t6*c0
  100. this.F.mul(t6, c1), // t6*c1
  101. this.F.mul(t6, c2)]; // t6*c2
  102. }
  103. div(a, b) {
  104. return this.mul(a, this.inverse(b));
  105. }
  106. square(a) {
  107. const s0 = this.F.square(a[0]); // s0 = a^2
  108. const ab = this.F.mul(a[0], a[1]); // ab = a*b
  109. const s1 = this.F.add(ab, ab); // s1 = 2ab;
  110. const s2 = this.F.square(
  111. this.F.add(this.F.sub(a[0],a[1]), a[2])); // s2 = (a - b + c)^2;
  112. const bc = this.F.mul(a[1],a[2]); // bc = b*c
  113. const s3 = this.F.add(bc, bc); // s3 = 2*bc
  114. const s4 = this.F.square(a[2]); // s4 = c^2
  115. return [
  116. this.F.add(
  117. s0,
  118. this._mulByNonResidue(s3)), // s0 + non_residue * s3,
  119. this.F.add(
  120. s1,
  121. this._mulByNonResidue(s4)), // s1 + non_residue * s4,
  122. this.F.sub(
  123. this.F.add( this.F.add(s1, s2) , s3 ),
  124. this.F.add(s0, s4))]; // s1 + s2 + s3 - s0 - s4
  125. }
  126. isZero(a) {
  127. return this.F.isZero(a[0]) && this.F.isZero(a[1]) && this.F.isZero(a[2]);
  128. }
  129. equals(a, b) {
  130. return this.F.equals(a[0], b[0]) && this.F.equals(a[1], b[1]) && this.F.equals(a[2], b[2]);
  131. }
  132. affine(a) {
  133. return [this.F.affine(a[0]), this.F.affine(a[1]), this.F.affine(a[2])];
  134. }
  135. mulScalar(base, e) {
  136. return fUtils.mulScalar(this, base, e);
  137. }
  138. exp(base, e) {
  139. return fUtils.exp(this, base, e);
  140. }
  141. toString(a) {
  142. const cp = this.affine(a);
  143. return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])}, ${this.F.toString(cp[2])} ]`;
  144. }
  145. }
  146. module.exports = F3Field;