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.

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