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.

110 lines
3.0 KiB

  1. const bn128 = require("snarkjs").bn128;
  2. const bigInt = require("snarkjs").bigInt;
  3. const babyJub = require("./babyjub");
  4. const assert = require("assert");
  5. const createBlakeHash = require("blake-hash");
  6. const GENPOINT_PREFIX = "Iden3_PedersenGenerator";
  7. const windowSize = 4;
  8. const nWindowsPerSegment = 50;
  9. exports.hash = pedersenHash;
  10. exports.getBasePoint = getBasePoint;
  11. function pedersenHash(msg) {
  12. const bitsPerSegment = windowSize*nWindowsPerSegment;
  13. const bits = buffer2bits(msg);
  14. const nSegments = Math.floor((bits.length - 1)/(windowSize*nWindowsPerSegment)) +1;
  15. let accP = [bigInt.zero,bigInt.one];
  16. for (let s=0; s<nSegments; s++) {
  17. let nWindows;
  18. if (s == nSegments-1) {
  19. nWindows = Math.floor(((bits.length - (nSegments - 1)*bitsPerSegment) - 1) / windowSize) +1;
  20. } else {
  21. nWindows = nWindowsPerSegment;
  22. }
  23. let escalar = bigInt.zero;
  24. let exp = bigInt.one;
  25. for (let w=0; w<nWindows; w++) {
  26. let o = s*bitsPerSegment + w*windowSize;
  27. let acc = bigInt.one;
  28. for (let b=0; ((b<windowSize-1)&&(o<bits.length)) ; b++) {
  29. if (bits[o]) {
  30. acc = acc.add( bigInt.one.shl(b) );
  31. }
  32. o++;
  33. }
  34. if (o<bits.length) {
  35. if (bits[o]) {
  36. acc = acc.neg();
  37. }
  38. o++;
  39. }
  40. escalar = escalar.add(acc.mul(exp));
  41. exp = exp.shl(windowSize+1);
  42. }
  43. if (escalar.lesser(bigInt.zero)) {
  44. escalar = babyJub.subOrder.add(escalar);
  45. }
  46. accP = babyJub.addPoint(accP, babyJub.mulPointEscalar(getBasePoint(s), escalar));
  47. }
  48. return babyJub.packPoint(accP);
  49. }
  50. let bases = [];
  51. function getBasePoint(pointIdx) {
  52. if (pointIdx<bases.length) return bases[pointIdx];
  53. let p= null;
  54. let tryIdx = 0;
  55. while (p==null) {
  56. const S = GENPOINT_PREFIX + "_" + padLeftZeros(pointIdx, 32) + "_" + padLeftZeros(tryIdx, 32);
  57. const h = createBlakeHash("blake256").update(S).digest();
  58. h[31] = h[31] & 0xBF; // Set 255th bit to 0 (256th is the signal and 254th is the last possible bit to 1)
  59. p = babyJub.unpackPoint(h);
  60. tryIdx++;
  61. }
  62. const p8 = babyJub.mulPointEscalar(p, 8);
  63. assert(babyJub.inSubgroup(p8), "Point not in curve");
  64. bases[pointIdx] = p8;
  65. return p8;
  66. }
  67. function padLeftZeros(idx, n) {
  68. let sidx = "" + idx;
  69. while (sidx.length<n) sidx = "0"+sidx;
  70. return sidx;
  71. }
  72. /*
  73. Input a buffer
  74. Returns an array of booleans. 0 is LSB of first byte and so on.
  75. */
  76. function buffer2bits(buff) {
  77. const res = new Array(buff.length*8);
  78. for (let i=0; i<buff.length; i++) {
  79. const b = buff[i];
  80. res[i*8] = b & 0x01;
  81. res[i*8+1] = b & 0x02;
  82. res[i*8+2] = b & 0x04;
  83. res[i*8+3] = b & 0x08;
  84. res[i*8+4] = b & 0x10;
  85. res[i*8+5] = b & 0x20;
  86. res[i*8+6] = b & 0x40;
  87. res[i*8+7] = b & 0x80;
  88. }
  89. return res;
  90. }