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.

121 lines
3.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
5 years ago
5 years ago
5 years ago
5 years ago
  1. const Scalar = require("ffjavascript").Scalar;
  2. const blake2b = require("blake2b");
  3. const assert = require("assert");
  4. const ZqField = require("ffjavascript").ZqField;
  5. const utils = require("ffjavascript").utils;
  6. const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
  7. exports.F = F;
  8. const SEED = "poseidon";
  9. const NROUNDSF = 8;
  10. const NROUNDSP = 57;
  11. const T = 6;
  12. function getPseudoRandom(seed, n) {
  13. const res = [];
  14. let input = Buffer.from(seed);
  15. let h = blake2b(32).update(input).digest();
  16. while (res.length<n) {
  17. const n = F.normalize(utils.leBuff2int(Buffer.from(h)));
  18. res.push(n);
  19. h = blake2b(32).update(h).digest();
  20. }
  21. return res;
  22. }
  23. function allDifferent(v) {
  24. for (let i=0; i<v.length; i++) {
  25. if (F.isZero(v[i])) return false;
  26. for (let j=i+1; j<v.length; j++) {
  27. if (F.eq(v[i],v[j])) return false;
  28. }
  29. }
  30. return true;
  31. }
  32. exports.getMatrix = (t, seed, nRounds) => {
  33. if (typeof seed === "undefined") seed = SEED;
  34. if (typeof nRounds === "undefined") nRounds = NROUNDSF + NROUNDSP;
  35. if (typeof t === "undefined") t = T;
  36. assert(t<=6); // Force the same matrix for all.
  37. t=6;
  38. let nonce = "0000";
  39. let cmatrix = getPseudoRandom(seed+"_matrix_"+nonce, t*2);
  40. while (!allDifferent(cmatrix)) {
  41. nonce = (Number(nonce)+1)+"";
  42. while(nonce.length<4) nonce = "0"+nonce;
  43. cmatrix = getPseudoRandom(seed+"_matrix_"+nonce, t*2);
  44. }
  45. const M = new Array(t);
  46. for (let i=0; i<t; i++) {
  47. M[i] = new Array(t);
  48. for (let j=0; j<t; j++) {
  49. M[i][j] = F.normalize(F.inv(F.sub(cmatrix[i], cmatrix[t+j])));
  50. }
  51. }
  52. return M;
  53. };
  54. exports.getConstants = (t, seed, nRounds) => {
  55. if (typeof seed === "undefined") seed = SEED;
  56. if (typeof nRounds === "undefined") nRounds = NROUNDSF + NROUNDSP;
  57. if (typeof t === "undefined") t = T;
  58. const cts = getPseudoRandom(seed+"_constants", nRounds);
  59. return cts;
  60. };
  61. function ark(state, c) {
  62. for (let j=0; j<state.length; j++ ) {
  63. state[j] = F.add(state[j], c);
  64. }
  65. }
  66. function sigma(a) {
  67. return F.mul(a, F.square(F.square(a,a)));
  68. }
  69. function mix(state, M) {
  70. const newState = new Array(state.length);
  71. for (let i=0; i<state.length; i++) {
  72. newState[i] = F.zero;
  73. for (let j=0; j<state.length; j++) {
  74. newState[i] = F.add(newState[i], F.mul(M[i][j], state[j]) );
  75. }
  76. }
  77. for (let i=0; i<state.length; i++) state[i] = newState[i];
  78. }
  79. exports.createHash = (t, nRoundsF, nRoundsP, seed) => {
  80. if (typeof seed === "undefined") seed = SEED;
  81. if (typeof nRoundsF === "undefined") nRoundsF = NROUNDSF;
  82. if (typeof nRoundsP === "undefined") nRoundsP = NROUNDSP;
  83. if (typeof t === "undefined") t = T;
  84. assert(nRoundsF % 2 == 0);
  85. const C = exports.getConstants(t, seed, nRoundsF + nRoundsP);
  86. const M = exports.getMatrix(t, seed, nRoundsF + nRoundsP);
  87. return function(inputs) {
  88. let state = [];
  89. assert(inputs.length <= t);
  90. assert(inputs.length > 0);
  91. for (let i=0; i<inputs.length; i++) state[i] = F.e(inputs[i]);
  92. for (let i=inputs.length; i<t; i++) state[i] = F.zero;
  93. for (let i=0; i< nRoundsF + nRoundsP; i++) {
  94. ark(state, C[i]);
  95. if ((i<nRoundsF/2) || (i >= nRoundsF/2 + nRoundsP)) {
  96. for (let j=0; j<t; j++) state[j] = sigma(state[j]);
  97. } else {
  98. state[0] = sigma(state[0]);
  99. }
  100. mix(state, M);
  101. }
  102. return F.normalize(state[0]);
  103. };
  104. };